Professional Python Testing with Mocks

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what is going on guys welcome back in this video today we're going to learn how to professionally test our python code using mock objects so let's get right into it [Music] alright so we're going to talk about mock objects in this video today and a mock object is essentially a simulated object that mimics the behavior of some other real object for example an API a database a mail server something like that and the idea behind using mock objects is that when testing our code we don't want to actually test the functionality of an external API of a database of some mail server we want to test the functionality of our code so for example we might have a procedure where we send a request to an API we get a response we process this response we do something with it and then we want to see if this process works properly now in this process this external API that we're depending on might fail it might be unavailable it might have a bug for a couple of days it might produce some problems and we don't want to actually test the functionality of this API and we also don't want to have to rely on this API to see if our code functions properly so what we can do in this case is we can create objects that mimic the behavior of the API so we can send requests to this mock object and the mock object will actually return what the API should return in this case but we don't have to actually send any API requests and of course this can also be useful in general when you just don't want to send real requests while testing so for example when testing a mail server or when testing a functionality that uses a mail server you don't want to actually constantly send emails to actual people you want to test the process of sending emails because you're going to assume that the mail server works anyways this is not your code you're not going to test Microsoft's Office 365 Outlook server for example you want to test if your functionality if your code actually does the right things so this is the idea behind the mock objects and mock testing and we can use these structures in core python so I think from version 3.3 onwards we have this mock object in the unit test module which is core Python and before that we had to install a package called mock but since I'm using right now python 3.10 we're going to import it directly from core Python and we're going to start with a simple API example so I'm going to import requests by the way request is not a core python package so if you want to install it you have to say pip 3 install requests by the way I'm working on a new keyboard right now I have the US keyboard layout now even though I live in Europe so I might mistype a little bit more often than usual so I have to kind of get used to the Keys here so we're going to then import unit test itself and then we're going to also import unit test dot mock those are going to be the packages that we use and now the test case is going to be extremely trivial we're just going to have a function that makes an API call gets a response and then Returns the Json object nothing more than that very simple we're going to call this function get underscore user underscore data and it's going to have a user ID parameter here and again all it does is it basically sends a request and get request to some API I'm going to just make up some endpoint right now https uh slash slash and then API dot example calm I don't know if that API exists and then we're going to say users and then slash and then we're going to use curly brackets here to say user ID so this is an actual API call this is our actual function we're not mocking anything here this is our actual production function that we would use in our code and this function actually sends a request to this API example.com and it does the actual work and then what it does is it returns in our case very simple as I said this is going to give us a response and the response is going to have a Json format and we're going to return that this is our function and you can imagine this to be some functionality making an API call processing the data and so on in our case just returning a Json object now what we can do now is we can create a test class so we can say test user data for example and we're going to pass here as a class as a parent class unit test DOT test case this is now not mocking this is just basic testing here and we're going to define a function that we're going to call test get user data and this function should call the function the get user data function but it should call it in a specific way first of all the request itself we want to examine the request itself and we want to also get the response we want to mimic the response that we get so what we're going to do here first of all is we're going to pass a parameter and this parameter is going to be called mock underscore get now you can call this whatever you want you don't have to call it mock underscore get I call it mock underscore get and then we're going to add a decorator up here the patch decorator and by the way I did the Imports incorrectly what we need to do here is we need to say from unit test.mark I want to import patch and mock Mark with a capital m patch with a lowercase p um and we want to patch a certain function or yeah a certain function in this case and this function is requests dot get now the idea behind this patch is that when you pass this string here every occurrence every call of requested get will be mocked so this also involves all the functions being called inside of that function so if I call here get user data with ID 12 for example the requested get call in this function inside of this function here will be mocked so it's not actually performing this call we now have a mock object that we can use to to uh and analyze the behavior of this request function here so uh that's the idea behind that now what we're also going to do is we're going to Mark the response so we're going to say mock response here is going to be equal to mock this is now an instance of the mock class which is very flexible so we're going to just assume now that the response dictionary we're going to just artificially create a response dictionary and this response dictionary will have some data it will have a name let's say the name of the user is in this case John and we have some other data about users so for example an email address the email address is going to be John at example.com and um this is what our mock object will return so this is what our function our request here will return as a response in our test case we're just going to assume that this is it remember what we're interested in is analyzing our function even though in this case the example is a little bit abstract because we're not doing anything we're not interested in testing this line here we're not interested in testing the API call we're interested in testing whatever comes after that and before that so we're going to just say now artificially this is what the API call will return and we do that by saying mockresponse dot Json dot return value okay what happened now dot return underscore value mock response Json return value is going to be equal to the response dictionary so we artificially say our response will have this dictionary as a Json response this is what we want to artificially create here and then we're going to say Mark underscore get which is our parameter that is patched with request.get here I want to say that the return value Y is python automatically turning return into return value equals mock response so the return value of our request is going to be this mock object here which has this as a Json return value now we can just go ahead and say user data equals and we can say get user data for example one and now we can assert something we can assert for example that a certain URL is called so in our case we want to make sure that if we pass one here at this URL with one has been called so I can copy this here and I can say that uh for the mock get so for the request get function I want to assert that it has been called with so a sir called underscore with I want to assert that it was called with the following string and the string is https example and not user ID but one so I want to make sure okay when I call it with a one this is actually the URL being called I want to make sure that this is the case even though again we don't make the actual API call we pass the actual parameter and we want to be sure that this is the result of this string that we format up here and then we want to also say for example self dot assert equal we want to make sure that something is the case that the user data that we get as a response from this object here or for the from this function here is actually the response dictionary and in our case this is of course going to be true and we can say if underscore underscore name underscore underscore equals underscore underscore actually in quotation marks underscore underscore main underscore underscore then we're going to say unit test dot Main uh what's the problem here oh of course there you go so you can see test okay now if I change this to two it should fail because it's not calling this URL you can see that we have a difference in what we expect and what we get so this works this is how you can test a request with a mock object now let us move on to a second example we want to do the same thing with an email client so this is again very simple we have here an API call we just analyze how the function is being called and what the return value is now let us try something else we're going to import a couple of packages import SMTP lip we're going to import uh email or actually from email dots mime dot multi-part we're going to import this class here and then from email mime dot text we're going to import my text and uh then we also want to import here any as a cap all an uppercase all in capital letters and we're going to Define a simple function sent underscore email and this function takes the parameters uh SMTP underscore server SMTP underscore Port then we have uh a from address and we have a two address and we have of course a subject and a body um yeah and would want to make sure here now is that the email is sent properly without actually using a mail server without actually sending an email so we're going to say here message equals my multi-part and then we're going to say message from uh is going to be from address and then we're going to say message two is going to be to address and then we're going to say message subject is going to be equal to subjects and then we're going to say message dot attach even though you could also just do it in a different way but we could also say message attach mine text and we want to have the body and we want to have the type being plain text so this is constructing the message and then we want to say server equals SMTP lib dot SMTP uh want to pass the SMTP server we want to pass the respective SMTP Port that was passed as a parameter here we want to start TLS uh so server Dot dot start TLS want to say server Dot Login and now we're going to use the from address as a login and we're going to say here uh my password is going to be the password this is something we're also going to check for in a second here um text equals message dot ask string and then want to say server dot send mail and we want to say from address to address text and finally server dot quit this is our function here now this function again is an actual function that we would use in production this is not some mock function this is something that when you call it when you just call it in your code we'll actually send email if you pass a proper server port and if you have the correct password and the correct email here this is not a mock function this does the actual thing but we can mock it we can Mark certain aspects of it so that we can test it without actually accessing the SMTP server without actually logging in and without actually sending the email and we do that by saying for example test email as a class here will extend again from or inherit again from unit test test case and we're going to say here the function is going to be test underscore sent underscore mail and here again we want to have a parameter and this parameter will be the mock SMTP server so mock SMTP and we're going to patch this I'm going to say patch and we want to Patches SMTP lip dot SMTP meaning again when smtplib.smtp is called so when we use this Constructor here this is going to be mocked this is not going to actually log into an SMTP server with a port or connect to an SMTP server with a port this is going to actually be mocked we're going to have a mock object representing this um and what we want to do here is we want to say instance equals uh SMTP or mock SMTP dot return value um and this basically uh basically means that we're mocking the resulting connection so this here marks the uh the SMTP connection or we replace the actual SMTP connection this year uh mocks all response all functions being called so we're going to say instance equals that we're going to say sent sorry sent underscore email and we're going to pass here some SMTP server for example SMTP dot example.com with a certain Port 587 for SMTP usually uh and of course we need some more stuff we need to say that I want to send from my mail at example.com to his mail add example.com now let me just move the code a little bit so I'm not blocking it with my camera and then we're going to say you want to have some subject I'm going to just say subjects I'm going to just say mail content um yeah so that's the line that we want to call this is the function call and what we want to do now is we want to analyze how the function call happened because again remember I'm repeating myself here but remember what we're trying to do here is not trying to test whether the SMTP server Works whether the connection to the SMTP server works we know that it does or we assume that it does we want to know if our process around it works if the function has been called correctly if the parameters have been passed correctly if everything has been done correctly we're not interested in actual in the actual testing of the connection to the SMTP server this can be done separately if we want to but this is not what we would use mock testing for so we can say now mock SMTP assert that it has been called with so assert underscore called underscore with I want to assert that it was called with the parameters SMTP Dot example.com import 587 so this line basically says okay we're mocking the whole thing but we want to make sure that we're actually connecting to the correct server with the correct Port because if you change something in your code because you're doing some experimentation some stuff and you run this test and you maybe use some other SMTP server because you're playing around this test will show you that you're not actually using the proper SMTP server uh and then we're going to say instance which is again our return value from the mock SMTP here we're going to call the sub functions here so star TLS login sent mail and quit and we're going to assert certain things about them so we want to say start TLS we want to assert that it was called with nothing so assert that it was called essentially and then we're going to do the same thing here for the login you want to assert that was called with the correct credentials so we want to say okay it has to be called with my mail at example.com with the correct password which is my password my password like this and instance dot uh send mail I want to make sure that this is called now let me just copy this a couple of times here I want to assert come on this is the new keyboard send mail assert that it was called with my mail and then his mail at example.com and then with the text so basically what the text is doesn't really matter so we're going to say any this will be imported this for this would we import at any four saying okay we want to call it with those um sender and Target emails source and destination males from two males and the text doesn't matter so whatever is the text this is not part of the text test necessarily we don't want to assert a certain text you want to say okay this has to be the case but we don't care about the actual content of what is being sent um and then finally you want to say quit has to be called as well without parameters but this has to be the case and then finally again we say if underscore underscore name underscore underscore equals and then on the screen score Main underscore underscore if that is the case so if we're not importing but we're actually running call the Main tests and again I'm using just one equation equal sign here and you can see the test runs because everything is done properly again if I change something like the password to something else here you can see we fail because not the correct password was called yeah so you can see the value of this hopefully those were quite abstract examples but the idea again is that you have um that you have certain objects that you don't have to really call you don't have to really call the API you don't have to really connect to the database and execute statements you don't have to really send emails to actual uh recipients you can just mock the behavior you're going to create this these mock objects that behave exactly like the mail server should behave like the database should behave in like the API should behave but you're not actually dependent on the actual objects and you're also not sending actual requests which can sometimes take more time you're assuming that they do their job properly and you're testing the code that interacts with those objects so that's it for today's video I hope you enjoyed it and hope you learned something if so let me know by hitting a like button and leaving a comment in the comment section down below and of course don't forget to subscribe to this Channel and hit the notification Bell to not miss a single future video for free other than that thank you much for watching see you next video and buy
Info
Channel: NeuralNine
Views: 45,549
Rating: undefined out of 5
Keywords: python, mock, mocks, python mocks, python mock, python testing, unittests
Id: -F6wVOlsEAM
Channel Id: undefined
Length: 21min 19sec (1279 seconds)
Published: Mon Jul 03 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.