Pytest Tutorial – How to Test Python Code

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome to this comprehensive video course on py test the powerful testing framework for python throughout this course you'll gain a deep understanding of piie tests features best practices and the nuances of writing effective tests and at the end you'll learn how to use chat GPT to help you write tests quicker Farhan Ali created this course he is a freelance web developer who specializes in both design and full stack web development what is going on you guys and welcome to this video brought to you both by rhythmic and free code camp now in this video we're going to be covering testing in Python and this is aimed mainly at beginners to introduce you to this world but also for professionals as well who are also curious in using pest in their day-to-day lives so first of all what is py test now py test is of course a testing framework it's in the name and also in the title of this video but what comes out of the box well first of all one of the great features of pie test is this thing called autodiscovery of tests now what does that mean well autodiscovery of tests all that means is that P test has the ability to pick up tests based on the way we name them so for example we can name a test test underscore and then the name of the file or we can have it as the name of the file and then underscore test and it will know that in this file there will be tests and usually IDE so for example if you're using py charm we'll also be able to detect this and you'll be able to just click play and run your test the other naming convention is also when we have test underscore and then the name of the function that that will then imply to the tpy tests that this is a test and you can also run those individually now another great thing around autodiscovery of tests is that there's no explicit registration needed so unlike some other Frameworks where you might need to build a list or a registry of tests manually P test automatically identifies which functions and methods are tests based on their names and it also simplifies test execution with autodiscovery you don't need to specify each test case to run manually you just run P test command and it will discover all the tests and you'll see that later on the next thing that comes with P test is Rich assertion introspection which sounds like a very fancy term but all that means is that with Rich assertion introspection that when a test fails in P test we get a really nice breakdown as to why that test failed so we get really nice clean reports that make it very easy for us the coder or the developer to understand so we know exactly where our test went wrong or not even just tests but what we're testing went wrong and another great thing that comes with P test is this support for parameterized and fixture based testing now what that allows us to do is it basically means that we can easily run a test function multiple times with different arguments ensuring that a broad test coverage with minimal code is that so we could test that a certain number will show up depending on the value and we can give it like a list of numbers and it will just run it for each one so we don't have to write each test manually which saves a lot of space and also provid us with a it makes it very readable for the uh developer now we've explained what pie test is the next is why do we need py test well first of all one of the great things with py test or the reason why you should be using p test is that it has a very simplified syntax pest allows you to write code or write test cases using plain assert statements which is the assert statement that comes with python without needing special assertion methods like assert equal or assert true which you may find in other uh python test testing libraries such as unit test or nose another one is of course Rich assertion introspection as mentioned earlier providing us with clear reports when our tests go wrong it also has a very powerful fixture system and what that means is pest fixture system is both flexible and Powerful allowing for setup and tear down operations so we can easily include operations to run before a test starts and also write in tear down code so when a test is finished we can clean it up we also have these scope or these fixtures can also have scope and auto use settings meaning we don't have to keep let's say we're testing an object we don't have to keep creating that object each time we can have a place where the object is created and we can use it for all of our tests this still might sound a bit confusing but we'll see it in the code and you'll get a better understanding of how powerful this fixture system actually is another great feature of py test or why you should use it is compatibility as py test can run tests for unit test or nose so other python testing libraries so you can kind of easily migrate over to py test if you're using another one and so it doesn't really get in the way if you want to try out a different testing Library P test will still work and that's why I want to focus on P test for beginners as once you understand the concepts of P test you can easily translate them over to different projects where you use different testing libraries and finally another reason why you should use py test is the extensibility now pest has a very rich plug-in architecture with many third third party plugins available so for example if you have ajango application and you want to start testing it there is of course a pie test Django plugin that you can use there as well which is tailored towards Django and you can just plug that in and get rolling with it but otherwise that's the reasons why you should be using py test it's enough talk for me I mean it's one thing talking about the theory but now we need to see it in action so I've gone ahead and opened up a new project a new python project I am using virtual environment in this example however you don't necessarily need to as we're not building out a fully fledged project we're just using pie test the library P test so whether or not you want to use it it's a matter of preference at this point but I've opened up in py charm you can also use vs code however I do recommend py charm for testing especially testing and you can also use the community version I am here as well and that's because the the way tests are integrated into py charm it's very easy to get up and running with it however we're also going to use a command line for this as well so regardless if you're using VSS code to notepad it doesn't matter it still work so first of all we have our empty project we need to go ahead and make the necessary installations so the first one I'm going to to make and the only one I'm going to make is PIP install and then pie test hit enter and in this one we're using the version 742 which I think which I guess is the latest version right now it doesn't matter I guess if you're using a I guess modern version of it it shouldn't really matter because the principles of py test and the way you use P test doesn't necessarily change so we have this version pest 742 now we need something to actually test because we don't have we don't have any code so there's no point testing so let's go ahead and create some functions we create a new python package I'm just going to call this source and within that I'm going to create a new file and I'm going to call this my functions and we're not going to add anything special here first we're just going to demonstrate how to write test how to write the most basic P test you can so first of all in my test we're going to have a function and all that does is add two numbers so this may be a throwback for a few of you folks as I guess this is tends to be the example a lot of books or people tend to use so return number one plus number two all right and let's just do one more we'll say divide say number one and number two and return number one divided by number two so pretty standard stuff but in this case the reason why we have that here is because we want to test it now the reason why I'm getting these lines is because I need to reformat so you'll see me do that from time to time in the tutorial that's just to stop the IDE from complaining all right so we have our source next let's create a new directory inside of our main project so the root of it and we'll call this tests like so now if you remember from what I was saying earlier in the presentation that what pest does is it has a great ability to pick up or figure out where our tests are going to be located so because we're calling this test you'll have an idea that tests are actually in here and within that and also it's good for us because we also know that teser in here because it's labeled and named correctly let's go ahead and create a new file and we'll say testore mycore functions all right so what are we going to do here so we're going to test our functions add and divide so let's get started we'll say import and then py test and we'll say import Source my functions as mycore functions all right so let's test our first one we'll say testore add and if you see here on pie charm you may also get this you probably will actually this play button right next to it that's because it's detected that this here is a test so py charm already has this great integration of tests so you don't really have to use a terminal but you can pretty much click this button and then the test should run but we're going to use a terminal in this example so we'll say clear and we can actually run this now and you may have already guessed it that this test should pass so we'll say P test and then tests and then test my functions and there we go we have one passed and at 100% because we only have a one test function and that test function is actually not testing anything but this passes because there's no complaints coming from a failed assertion so let's go ahead and actually write something in there so we'll say result equals my functions add and we'll say one and four so now we have a result so we know from our own intuition that this is going to be five so we'll go ahead and say assert results equals five so if this assertion fails then this is going to this is going to break and our test will fail however if it passes then we get a pass let's go ahead and test that so Pi test and then test my or test my function and enter and there we go we have 100% pass no complaints but what if we were to change this value and say six let's run it again enter and there we go we get a fail so it's telling us that our test ad failed and down here it's saying that where it fails so what line exactly and it's saying that assert result equals 6 is failing because result is actually five and we're saying that we want it to be six so yeah it's telling us what value that should be we'll set that to five so if you're working on a real life application you may be expecting a certain value but you're not getting that value back at least then you will know okay maybe something's wrong so you may go back either to fix your tests or to fix the application itself so there we go with our test ad but let's just quickly go over what this assert statement actually is so in Python the assert statement is a debugging Aid that tests a condition as an aid to debugging if the condition is true the program continues executing as if nothing happened so in our case it continues and there's nothing to continue to continue so there's a pass however if the condition is false and assertion error exception is raised which interrupts the normal flow of the program so if we go back here and we look at our error that we got we get here that it's an assertion error so every time an assert an assertion fails we get this assertion error that's why we're getting that value but that quickly addresses how assert works so you can see here that if this is not basically rendering to be true then it's going to break now let's go ahead and write our divide test function so here we'll say what should we call it let's just say divide so test divide and it's always good to make sure that you're naming your tests properly so divide in this case it's very basic we're just testing that divide works so result equals my functions do divide and we'll say 10 by 5 and for you Geniuses out there you should know that 10 ID 5 is 2 so we'll say results equals two let's go ahead and run that so here just clear this and then Pi test tests and then test my functions enter and now we have two little dots here at 100% rate awesome so that covers our very basic P test examples where we're just throwing a simple Asser to make sure the value that we get back from functions are the values that we expect but what if we were to test this by saying number one divided by zero because we know you can't divide a number by zero so what would happen there well let's go and try it out and actually let's go ahead and try it out on a different function so we'll say test divide and divide SP properly divide by zero all right so here say result equals my functions do divide and then we'll say 10 and zero and then we'll say assert and let's right now just say assert true so if we say assert true then this will pass but let's see what we get when we test a test divide by zero so let's just go into just expand this and we'll say p test and tests test my functions and we get a fail even though we have this assert true so why is that the case so here in our divide our divide by zero um test here so it fails here on this my functions. divide and that's because if we scroll down a little bit we get this Zer division error so division by zero is the cause of this zero division error so what if we want to test that type what if we want to say okay if I divide a number by zero I'm expecting this zero division error so we can actually do that in P test and it's very simple what we can do is say something like the following so above this as we know it fails on the function call we can say with P test dot raises and then we can say zero division error all right and we don't need this result CU we don't care about it anymore we just want to call the function without storing it let's go ahead and try this out so back in the terminal let's go ahead clear all that and then P test run it again and there we go we get three passes because what we're saying here is that we're expecting a division error when we call this function so even though the function itself fails or there's an error in the function we can test to make sure that error is there and that can be very important let's say You're Building A an accounting tool and you're dividing by zero you want something there too but just to kind of drive this point further if we go back to our divide function we can say if number two equals zero then we can raise and let's change it to a value error let's do that now if we go back and we run this again and if I just clear all that run it we get an error because we're testing for a zero division error but in actuality we're getting a value error so all we have to do here is just change this to Value eror all right so that's our test pretty much summed up uh or our very basic test summed up excuse me but we're only testing for number numbers what about strings like how would that work well it work the exact same way and so what we can do is we can use the add function and we'll say test add strings we'll say results equals my functions. ADD and we'll pass in I like and we'll say burgers now we can say assert result equals I like burgers because it will concatenate it so if we run this now and we go into the terminal and we say p test test my functions we get an error and that's good because you can see here that there we made a mistake where we need to add an extra space here see there like I like bu Burgers like burgers one word and then the what we're expecting is I like burgers is three separate words so let's run that again and there we go we get four passes looking beautiful and that is what you want to aim for as a developer but that brings us to the end of the first part of this tutorial which is looking at how to write very basic tests and now let's go over and start looking at how we can write class-based tests because right now all of these are function based tests so for our class based test the first thing that we need to do is write some classes that we can actually test so write some extra code CU right now all we have are two very basic functions which you can throw into a class base test however I want to kind of you know spice it up a bit and add some more a bit more complex code so inside source I'm going to go ahead and create a new file and I'm going to go ahead and call this shapes So within shapes what we're going to have is a class called shape and we're just going to use this for inheritance so shape and this is going to have a function that we'll override called area and we'll have another one and that will calculate the perimeter of a shape let's go ahead and add that in now let's go ahead and create a class which is going to represent a Circle and I don't know what is wrong with my spelling and this is going to inherit from shape the init so init this will take in a radius and we'll say self. radius equals radius then let's do the area and in order to calculate the area of a circle if you remember back Frome Elementary is we need the or we need to do pi r 2 so math or return math do pi multiplied by radius and squared so double asteris and a two and then for the perimeter we'll say return two multiplied by math P pi and then by the radius and it'd be a bit embarrassing for me to say that I actually have to look this up quickly before just to make sure I'm right as uh yeah sometimes I forget these basic things but anyway so now we have our class our class uh circle now let's go ahead and test it using class based tests so what we need to do is create a new file and we'll call this test Circle and it's a good practice to just name your class or your your test classes or test files based on what you're testing so in this case we're testing the circle so everything related to the circle will be in this file and here we'll say import P test and we need to import Source do shapes as shapes all right so to define a class-based test we'll say class and then test and circle and let's just put pass there now and this should pick it up anytime soon if it doesn't let's go ahead and just add test one and we'll just say assert true and again if you're using py charm you should see these play buttons show up now if you're not if you're using VSS code you may have an extension or there may be an extension out there which I'm sure there is where you can have the exact same effect but I'm more familiar with running or writing most my python code on pycharm but anyway now let's go ahead and if we just run this if you remember from the last example with my functions when we had a test I didn't do much it would still run in our case it should pass anyway because we're asserting that it is true so we'll say high test and then test and test Circle and there we go it's working let's actually just jump into test because we're going to be running everything through there all right so one of the cool things about tests or class-based tests is that it comes with two functions that can be quite useful the first one is the setup method now the setup method is there or is defined to run setup code before each test method so for all the test classes or test functions or methods that we write inside our class-based test the setup method will run at the beginning of each test and then like as a partner to it or to complement it there is the tear down method and the tear down method is there or defined to run tear down code after each test me method so after each one runs there is a tear down method so let's go ahead and just show that off we'll say set upcore method and we'll pass in this argument method now now the method argument just represents the test method that we're about to run so we can just say here print and we'll have a setting up and then method and then we'll have another one and we'll say tear downcore method and throw method in there print and setting or in this case tearing down and then the method all right so if we test this let's go ahead and use the P test command and say test Circle hit enter so we get a test passed but if we look at what the report generated we're not getting anything else so we're not getting our prints and we're not getting our tear down and the reason why we're not doing that is because when we call or when we use the P test command in our terminal we need to add A- s so we can say p test and then - s and now we get our print statement so setting up and then the method name so bound method test Circle test one and so it's just printing out the name of this test function that we have and then it's called tear down so if we did another test let's just copy test one and then here we'll say test two and if we were to go back to the terminal run it all again now we have four so we have setting up test one tearing down test one setting up test two tearing down test two now you're saying to me okay this is all well and good but this is useless I mean we're just printing stuff out well one thing that can be quite useful is that in the setup method we can have some something like say self do Circle and we'll say shapes do Circle give it a radius say 10 now for every method that we have this a circle object is going to be created so now we can access it in test one and instead of calling it test one let's say test radius so test radius and then here we can say CT and then self. Circle radius equals and we will need the math function so let's just import math and we know that the radius has to be math and we need pi multiplied by self do Circle dot uh radius and this here should be area and we should name this part here to area I don't know why I put it as radius but area and then this should be multiplied and then squared now let's go back and inside the terminal we'll say high test and then test Circle and there we go we get our test and you can of course add the - S as well um so like this but that is how the setup method can be useful now on our tear down we can also do something like delete self. Circle and in this case it's not necessary because it will be doing that anyway but for more complicated um more complicated programs that you're testing this tear down method can be quite useful along with the setup method however that's our class base test sorted out let's just clean it let's just finish it off really let's add a new test and say test perimeter because repetition with this helps and then we'll say result equals self. Circle do perimeter and then expected value equals 2 time math Pi Time by S do Circle radius and then we can say assert and result equals expected again spelling error expect am I just going crazy here oh yeah thought it was a spelling error we need to change that too sorry long day and there we go so that's our test parameter let's go ahead and test that out and we're all green cool so that's our class based tests like basically the overview of how class based test work how you can set it up and how you can use it with P test the next cool thing I want to show you are pie test fixtures so I'm back inside of the shapes file and what I want to do is go ahead and create another shape which we'll use to test well first of all we'll write our tests on and we'll then use fixtures to improve on those tests so down below I'm going to go ahead and create a new class this is going to represent a rectangle inherit from shape and we need to initialize it this will take in a length and a width self do length equals length and self. width equals width then let's calculate the area return self dot length by self. width and perimeter which we can do as return self dot length multiplied two [Music] and add that to self. width multipli 2 all right so we have now our rectangle now we need to go ahead and test it so let's create a new test file inside of the test directory we'll call this testore rectangle all right so let's just go ahead and use our functional tests and write the very basic test that we need so we know we need to test first let's just make the import import P test import Source do shapes as shapes then test area and here we'll say rectangle equals shapes Dot rectangle and we'll pass in 10 and 20 then we'll say assert rectangle do area equals or and rectangle or we'll say 10 multiplied by 20 all right new line reformat okay so we have our test area there now we can go ahead and run this just like we did before so we'll say test or P test and test rectangle and we have one pass all right now let's go ahead and create another test and we'll say test perimeter and here again we need a rectangle so we'll take this here paste it in and say assert rectangle. perimeter equals and that is 10 * 2 + 20 * by two now if we were to run this go back here clear and test it again we have two passes all right so nothing too special you're like okay we've seen this before what's so amazing about it well one thing we can do or one thing that you may have noticed is that our rectangle is being used and declared twice so we have two rectangles here both with a length of 10 and a width of 20 the values that don't really matter but the point is that we're repeating ourselves that we're needing a rectangle in both cases and we're creating a rectangle in both cases now if we were to use our where is it test Circle so if we were to use class based method we could or class base test we could of course have initialized it in the setup but what about with functional with functional we can use something called py test fixtures so we can do py test do fixture and then say how we can call it my rectangle you can name it whatever you want and all this will do is return a rectangle like so so now what we can do is we can literally plug this into each of our tests here so we can say my rectangle here and my rectangle here and we can remove this here this rectangle equals move it there as well and replace rectangle with my rectangle or whatever you named it so here and here go back up go back to the terminal let's clear that out High test and then test rectangle and there we go back to where we were but now we are using our py test fixture so just to kind of hone this in let's create another fixture and let's use that as well as our my rectangle so first of all let's just go back into shapes and I'm going to go ahead and create a new method which or not really create but at least overrides with the equals and here I'm going to say if is instance so if not is instance what we want to do here is say that if it's not a rectangle then we want to return false otherwise then we're going to check to see whether a rectangle is equal to to another so we'll say other and then rectangle and return false and then here we'll say return self do width equals other width and self do length equals other dot length so it's just a override for the equal so we can compare two different rectangles so now if we go back into test rectangle let's create a new fixture and we'll say fixture call this weird rectangle name it whatever you want I guess in a professional setting you'd want to name it something sensible but here we'll say shapes do rectangle and we'll say five and six all right now we can use this a weird rectangle and down below we'll say test not equal and we'll pass in my rectangle and a weird rectangle and we'll assert that my rectangle does not equal weird rectangle and we can go back to our terminal and just clear all that and say p test and test rectangle and there we go we have three passes but the important part here is that we're using our fixtures now one thing that is also important is that we can use something called con test so we can make our fixtures Global Within our tests so let's say for example you need the rectangle inside of test Circle for some reason um and you don't want to keep on declaring more um objects so you want it in a global play so you can access it easily now to do that is fairly simple all you need to do is inside of tests we have to create a file and we have to call this file conf test.py and in here this is is where we can Define our rectangles again so I'm going to go here and I'm just going to take this so my rectangle and weird rectangle I'm going to save that and go into com test paste it in of course we also need to import P test and shapes so import P test and import Source shapes as shapes there we go so now if we go back to test rectangle you can see that it's not complaining we can get rid of this and let's go ahead and run rectangle again so we'll say Pi test and test rectangle and there we go we have three clear tests and we have our my rectangle in use and our weird rectangle use which we' stored in a global place which is our com test we can also access in other files as well so inside let's say our test Circle we can do let's just come up with a silly example so test not same area rectangle and here we can pass in my rectangle like so and we'll say Circle equals self. Circle oh we already have the circle because we defined it up here so we can say assert does not equal or um self. Circle do area does not equal and then my rectangle do area all right now if we were to go into our terminal once again let's just clear all that and say p test and testore circle there we go everything is green and we're making use of our rectangle that we defined in com test accessible or we're using it in our test Circle file so this can be pretty useful especially if you've got like a really large code base where you have a lot of shared objects then the com test can of course be very helpful there so of course I wouldn't over abuse it like I wouldn't store everything in contest uh but this is just an example of how you can now the next thing that we're going to look at is something called pie test marking and parameterizing so the pie test Mark mechanism provides a way to add metadata to your test so you can think of it as tagging your test with labels that can influence how the test runs or is orted and the purpose of it is that you can label or tag your tests to categorize them for instance you might want to label some tests as being slow or some tests as be as to skip and um yeah which means that you can conditionally execute your tests so let's go ahead and do that so back in my functions we're just going to use add and divide as our examples because the purpose of Mark is just to demonstrate how they work not so much writing the test themselves so let's go ahead and if we I'm in my test we need my functions we need to go to test my functions so in here let's go ahead and let's look at the slow tag so let's say let's just import time at the top of this say import time go back down and we'll say test very slow um we will have let's take this here result actually let's just take all of this paste that in here and then above that what we'll do is just do time do sleep and we'll say 10 seconds so actually 10 seconds might be a bit too long for this video so let's do five so if we run this if we go into the terminal and say just clear that P test and then test my functions and it's still running cuz it's waiting for the last one and there we go it took 5 Seconds however this is a slow test and it didn't do anything it didn't alter the way our test work so everything passed and it managed to get to the end of this but it can be helpful for us to know that this test is going to be a slow one so we can say something like that so that's just telling us is ADD adding some metadata to state that this is a slow test so if you want to see the slow test or just or test the slow test we can say Pi test and then- M and then slow and it will only run the test my functions one because that's the only one that has a mark of slow and we're getting a warning Mark slow is this a typo I guess in this case no um but anyway it passs anyway this is just a warning it wasn't a failure and let's go back so that's the slow one can be quite useful let's say if you're I don't know if you're calculating something that takes a while to calculate you might want to add that in the next one is the skip uh test so let's go ahead and say at P test Mark and then Skip and we can add a reason to it as well just for ourselves can be quite useful and here we'll say this feature is currently broken and here we'll say test uh ad and let's just assume the ad is broken in this case we'll go ahead and assert that my functions do add one and two equals 3 and give that some extra room now if we go to our terminal clear all this and we run it again so we'll say Pi test test my functions enter you can see here that there's one that has an S there as well that means skip so we're skipping one test the other one is a slow one but here we are like that's a way to skip your test so you just add that in there another one is the X fail so we can go here and say p test and then Mark and then X fail and we can add a reason to this as well we can say uh we know we cannot divide by zero and we'll go ahead and do exactly that so test divides zero um say broken let's assume V my Z is a broken function all right so um let's go ahead and say assert um well let's just make the cor because we know it fails so we'll say my functions divide three four and zero let's go ahead and run this now so clear that and then P test tests my functions give that a second and there we go so if you go back here we have the s that represents our skipped one then we have these Green Dots which represent our past and then we have this x which means that we know this is going to fail uh and you can see here this kind of this breakdown four P one skipped one failed One X failed so it didn't fail in the literal sense that tests themselves fail um it failed given that we marked it as something that can fail as well so this is how Mark or marking can work and it can be again quite beneficial to just add some extra information around your tests there may be some tests that you know will break and you don't want to fix those tests or there's certain reasons why you don't want to fix them you can of course use this xfil then there is the skip which just means that yeah you want to skip this test um and maybe you'll come back to it later on uh but you want the test in there just as a reminder and then it'll also be useful for other Engineers that you're working with so they know oh wait why is it skipped there's probably a reason for it and they'll know the reason so the mark pest Mark can be a very useful feature mainly for us as engineers and also for your testing as well depending on how you want to see it but anyway that's covered that or that covers P test marking now we'll look at parameterize so so for the example with parameterizing what we're going to do first is back inside our shape so we're going to add our last shape and that's going to be a square so we can actually inherit from our rectangle and the way we can do that is by saying class and then Square inherit from rectangle and here we'll say in it and it will just give it a side length and then here we can say super and we'll pass in the side length for the initializer and side length for the so for the width and the length all right so that's our Square sorted out so let's go ahead and create a new file inside of tests and we'll call this one test Square all right so for this let's go ahead and make the necessary Imports so P test and import Source do my functions actually shapes as shapes all right so what is this whole thing around parameterizing so imagine you have a light bulb and you want to test it with different brands of batteries to ensure that it works with all of them so instead of writing each uh separate test for each battery uh it would be more efficient to actually just write one test and run it for each battery brand now of course you can try this out with a full loop however full Loops can get a bit messy and it just kind of ruins readability after a while so instead what the team behind P test have done is created this parameterized concept so the way we can use it is let's say we want to calculate the area of a square but we want to give it multiple values so let's just first Define find it so test multiple Square areas and it will take in a side length and we'll Define that in a second as a parameter and a expected area and the way this will work is what we'll say is assert and then shapes do shape and pass in the side length do area equals the expect area now you're wondering okay where are these values coming from they're not coming from the com test because we haven't defined it there well the way we can do that is here we can say at pest. Mark in but this time parameterize and here we'll Define the first parameter which is side length and then comma and then expected area and then we need to give values for both side length and the expected area so to do that we'll say it's going to be a list the first value of this topple so we'll have a list of topples and inside the first topple the first element is going to refer to the side length and then the second one is going to refer to the expected area and let's create a few of them cuz right now that's just one and then we'll do four and 16 and we'll do say nine and 81 let me just format this to stop it from complaining all right so what do we have so we have this parameterized Mark that we've placed on top of this test multiple Square areas then we have side length and expected area now side length refers to the first elements of each of the topples that are in this list so 5 4 and 9 the expected area however is referring to the second element of each of these uh the second element of each topple so 25 16 and 81 now we can actually just go ahead and run this so let's go ahead and clear this out and we'll say Pi test and then test square and we get an error because shape takes no this meant to be square it's good job that we're testing to see this error and then run it again and there we go and you can see here that we get three dots and that's because we have three different topples inside of our list now you can of course create another one so we say random here and if you want to use that you have to add another value to this as well like so so that's how parameterizing works now let's go ahead and do a bit of practice let's use it again on the perimeter so we'll say here we'll first add add our decorator Mark and then parameterize and for the perimeter we'll have a side length and comma and we'll call this one expected perimeter and then what we can say in this is the topple is going to be first one let's say three and the perimeter for that is going to be 12 then we'll have another one we say four and the perimet that is going to be 16 and then we'll say do another final one five and the perimeter of that is 20 and then we'll say Define test multiple perimeters and then we'll say the side length and expected perimeter and we'll do the exact same thing so ass set and then shapes do shape and throw in side length do area equals the expected perimeter and this should not be area this instead should be the perimeter and there we go let's go back into our terminal and if we were to run this now we get a a bunch of M errors because we have fail test multiple Square areas in parameterize the number of names expected ah it's this one here we need to get rid of this random run that again shape again so another one so this has to be square don't know why I miss that but this should be square go again and there we go now we have six tests but we've only by looking at it at face value just written two tests so parameterized can be very useful if you want to try the same test with different values to see what output you get rather than writing like a for Loop where it gets all messy so yeah definitely use parameterize when you need to it can be very powerful and very useful for developers who are reading it later on so again yeah this covers the parameterize parameterizing with py test now let's move on to the next topic so for the next topic we're going to look at something a bit more advanced and that's called mocking now mocking is a powerful testing technique which is used to isolate the system that we're testing and replace the external dependencies with controlled implementations called mocks so when might you use mocking now imagine you're writing a or you're writing code that fetches data from an external API using let's say the request library and you when writing this test you don't want to actually call the API itself because it might be slow it might cost money or affect rate limits and depending on the api's actual data as that is subject to change it might cause your test to fail so we don't want to depend on the API itself let's say we just know what the API is going to respond and we want to test that the same may also go for for testing a database so you might have a test that is testing let's say getting a user from a database and you don't want to depend on the database itself as you know the connection might be disrupted and therefore your test might fail so that's where mocking can come into play now I'm talking a lot so let's go ahead and actually code an example up and see how useful mocking can be so first in the source directory I'm going to go ahead and create a new file I'm just going to going to call this service and within that what we'll do is create a dummy uh database where we'll get a user so we'll say our database equals and in there we'll say one that will represent the ID we'll have Alice in there two we'll have Bob in there and three let's say we'll have have Charlie in there all right now what we'll do is create a function which will get user from DB and it will take in a user ID and it will return our database. getet user ID so pretty much working a bit like if you're using an omm it might be similar but in this case we're just mocking it with a database or actually we're not mocking it in the sense of testing this is let's just say this is actually our database and we'll mock it in a second let me just format this and then let's create a new file inside of test and we'll call this one test service and enter all right so how do we actually mock this so first of all let's make the necessary Imports let's import py test we need to import Source do service let's say service and let's leave it at that so there is another import that we'll need and actually let's just do that now so let's go ahead and say import right there import and unit test and then mock as a mock all right so remember right at the beginning of this video we were talking about how you can use other testing libraries within P test without any issues so we're doing that exactly here and the reason why you don't need to install this is because unit test comes with python I think from 3.3 version 3.3 and onwards you'll have unit test with every python installation that you make so you don't have to make a installation here and mock is inside of there and we'll use that for this all right so let's go ahead and create our test so test get user from DB and let's just put pass there the first thing that we need to do is add a decorator to it and that will come from Mock and we'll say patch and then we need the route or the path to our basically the path to our function so we'll say Source do service. getet user from DB and so that's going into our source and then our service file and then our function which we called get user from DB then we need to map that to an argument here so a bit like how we did with fixtures so what we'll say or with parameterizing or parameterize as we looked at earlier we can say mock get user from DB and this doesn't have to match this um so this mock part this the naming convention there's nothing strict here I just named it that for readability but you can call this whatever you want so it doesn't matter then we'll say Mock and then get user from DB and we'll say that the return value is going to be mocked Alice and then we'll say username equals and we'll say service dot get user from DB we'll put in the ID one and then we can say assert and then username equals mocked Alice so let's just quickly go over what we've just done once again now we're using the patch function from mock to replace get user from DB so we're saying use this function that we've defined in our source service and replace that with mock get user from DB and then here we're saying that the return value from this function call so whenever we call it in this test so in this test get user from DB we want the result to be mocked Alle and then here that's where we're fetching from our database that's when we're actually making use of our get user from DB we call it we pass it in an ID and then we're saying assert username equals mocked Alice because we know as Engineers so in a real life setting you will know that when you call this it will return a string and so if anything changes you will have to adapt this test of course but that's how this is working here all right so so that sums up the database test let's actually go ahead and run it so let's go into terminal and we'll say p test and then test service enter and we get a pass so there we go now if we were just to replace this with say that and then we run this or maybe if I use a terminal instead so P test we're getting an error because a moed Alice the return value that we're getting from this so get from get user from DB does not equal ASDF ASDF so there you go so in this case we're not testing whether or not the database works or not we're just testing to make sure that the response we're getting is what we expect is what we would expect so that's where mock mocking can be quite useful but this is a very simple example of mocking let's actually use it with an API so the first thing that we need to do is back inside the root of our project let's pip install requests so we need this request Library I just installed it with Pip instore request just here now back inside service we're going to go ahead and make an API call with that so we'll say import requests and what we're going to do is make a call to this website called Json placeholder and you can go to Json placeholder do type I code.com and here it just gives like free fake API for testing and prototyping which can be quite useful for our case for example and we're going to use the users endpoint so this one here you can use whatever endpoint you want just going to go with the users so when we fetch or we do a get request we're going to get this here so back in our code let's go ahead and create a function which will get the users so down here we'll say get users then here we'll say response equals and we need to we've imported it yep requests.get and we need to paste in the URL so this URL here copy that paste it in with double quotes and then if if the response. status code equals 200 meaning that the request was successful we'll return response. Json and then here we'll say raise requests. HTTP error so if there is an issue if it's not 200 then we want to raise a HTTP error all right now let's test this so like I said when we started talking about our uh mocking is that you will use mocking for something like testing or fetching from an API but you don't want to test the API itself the API is someone else's responsibility we're just testing in our case that we get the response that we want uh or we're getting the expected data that we want so remember actually calling an API in a test might not be the most economical thing to do uh it might actually not be the most efficient thing to do as well because apis can be slow so let's go ahead and use or test our function so the first thing that we need to do is of course map it with the patch so we'll say this mock do patch and we want to mock the request.get and I'll explain it further in a second so requests so make sure it's s doget and then we'll say testore getet users and Mock undor getet and then we'll say pass so let's just quickly explain this so we're testing our get users but we don't want to test necessarily the function or we do want to test a function but we want to mock the request.get so whenever we call request.get within this which we will because we'll be testing the function then we want to mock we want want to get a certain response so let's go ahead and say mock response equals mock mock like that and then we'll say mock response. status code and don't worry if you're confused because I found this very confusing when I first learned it and then mock response. Json and then return value equals and we know that the data looks like this but because we already know that we can shorten it so we'll say something like ID usually you would use like an exact example of it but for the purpose of this it doesn't matter because we already have an idea name and then John do and then mock getet do return value equals mock response and then data equals API or service. get users and then we'll say SE data equals ID one and name John do okay so to explain it what we're doing here is where so let's start from line 18 so we're calling this get users and within get users we're using request.get and in our test this is what we're mocking so we're saying whenever this is going to be called within our test we want it to come back with a response and the response that we want is in the form of this so This Json return value ID one name joh do because in our service response as this Json that we're returning so if the status code is 200 then where response Json is going to be returned and we want to say when this is returned and it's successful then it's going to look like this dictionary here and then we also want the status code so we're sending that to 200 and the reason why we're not just saying mock response Json equals dictionary is because the difference between status code and Json with our request.get response is that status code is actually a property and Json is actually a function or a method call so that's why we have to add this do return value so let's go ahead and test this now so clear and then Pi test test now we're outside so tests and then test service enter and we have two successes that means our data is this the value that we're mocking to json. return value and we can also say that or in our case it doesn't really matter we can't test this because our service is returning the response. Json anyway but to drive this a mocking Point further if we go back to our service we can see that if the status code is not A200 then we should get a HTTP error raised so we can go ahead and use our mocking power to make sure that that is the case so we'll say mock do patch and then requests.get and we'll do here test test get users error and then mock unor getet and within here what we'll do is say mock response so we'll take these two and paste that in and set the status code to 400 and then we'll say mock uh Moore getet dot return value equals mock response and then we'll say with it test. raises requests HTTP error and API or service. get users it should now work so let's go ahead and run it and once we run it we get a pass because we're saying that the status code is a 400 so with with that in mind we should get a raise a HTTP error now if we were to change that to a 200 and run it we get an error because it did not raise even though we have a 200 we were expecting a raise but instead we got a test fail so that should give you a good idea or hopefully gives you a good idea as to how mocking works with python testing now it might be a bit of a tricky thing to grasp at first it is a bit of a weird concept it was definitely for me however one rule of thumb that I would apply is when you want to use mocking or if you're kind in a bit of a dilemma if you want to use mocking or not I tend to use it when my tests are dependent on external programs that can give or cannot guarantee the same result each time for example if you're testing an API you cannot always guarantee that if you give it certain inputs you will get the exact same output each time because you know an API can of course crash it may have some downtime or whatever or may may take to some time to to actually give a response depending on the day or situation so you can't really guarantee that and your tests need to guarantee that you always have this result when you make a certain call to a function or a program so keep that one in mind and definitely play around with mocks as they can be very powerful when used correctly now let's move on to our final topic where we'll look at how we can use artificial intelligence to help us write our tests so in order to test AI when it comes to writing our test to see how well it can write python tests head over to open.com and there you'll have access to chat GPT by clicking on try try chat GPT now I already have an account I have a pro account which costs around I think $20 a month and it's definitely well worth it especially if you're a developer as the value that you get out of it is substantial but we'll also try it out on the free version so the 3.5 version and on the more upto-date version chat GPT 4 so I've already signed in and this is my account so this is my prompt I can click on either chat GPT 3.5 or GPT 4 with the 3.5 model this is available on the three version so if you're not paying for it you will have access to this and let's go ahead and see how useful this will be when it comes to writing our tests but before we do any of that what we need to do is go ahead and write some more code so in our source I'm just going to go ahead and close all of this and what we'll do is create a new program or a new class inside of this we'll call this school dopy and now this will represent or this will hold a classroom and that classroom will have a teacher and a number of students so let's write it up let's go ahead and say class classroom and say in it can initialize it with a teacher and students and we say course title and then we'll say self. teer so all the standard stuff or initializing a class self do students equals students and self. course title equals course title all right then we'll have a function where we can add a student and we'll pass in a student to this and we'll say if the length we don't need the parentheses so if length of self. students is less less than or equal to say 10 then we will add a student so students. append and student otherwise we want to raise an exception let's create our own exception over here we'll say class too many students sohit from exception we'll say pass just here now back down here we will say otherwise raise too many students then we'll do remove students so remove student this will take in a name and we'll say for student in self. students then if student name is equal to name then self. students. remove and then student and finally we'll break and the last one we'll add is say change teacher and we'll say new teacher say self. teacher equals teacher or new teacher all right so that's our classroom the next thing that we'll add is a class that will just represent a person so nothing too fancy person and this will take in in name and self. name equals name and then class pass teacher We'll Inherit from person say pass and the same goes for the student so student inherit from person and we'll say pass as well all right so just to quickly run through what we have we have a an exception to many students uh which we use in the remove students so or in the ad students so if there're too many students if there are more than 10 students then the if it's the number of students is 10 or more or less then we'll add a student if it's more then we'll raise the exception then we have our initializer where we set our teacher our students and course title and we can also remove a student as well as change the teacher then we can then we have our person class and then that just takes in a name and our teacher and student inherits from that all right so let's see what our AI makes of this so I'm just going to copy all of of that and what I'm going to do is back I'm just going to close this and then back in here we'll say using p test and the functions that come from it such as fixtures parameterize about correctly I hope uh raises and Mark wherever necessary test the following code and theme it after Harry Potter because after all we are using the classroom teacher student so why not make it a bit more creative and colon and then paste in the code enter see what we get so using p test and the functions that come with it such as fixtures parameterize razes and Mark wherever necessary test the following code and theme it after Harry Potter maybe that could be worded a bit better but anyway so to test the given code and theme it after Harry Potter you can use P test along with fixtures parameterize raises and marks here's how you can write tests in for the classroom so let's see we have a fixture defined for us which is Harry Potter and it's setting Harry Potter as a t I don't know how to feel about that one maybe yeah that's that's weird because then hmani gr is a student and Ron weey is a student as well anyway maybe Harry Potter is doing well in class he's now been leveled up to being a teacher and then we have the Hogwarts classroom as a fixture has an empty list of students the teacher is Harry Potter then we have our students and the class is defense against the dark Hearts um so so far it's theming all right I think the only thing think it got it a bit wrong is Harry Potter being a teacher but anyway then test the cases for the classroom class so test classroom creation and teacher name Harry Potter this and then so what is this doing test cases or the classroom class oh okay it's just making sure that the fixture that we have is properly defined then test add student we're adding herione Granger to the class and Ron weas and the length of it is now two because originally we had zero okay that works test add too many students so now we're adding 10 students to this and then finally and that's just like random students so generic students set to the name student with P test raises too many students maybe I mean it is 10 students so I think parameterized would have been a bit too much here but the for Loop makes sense then we're adding a Min Granger and it should raise too many students because that is more more than 10 then test remove students so we're adding Hamman and Ron then we're saying remove hmani Granger the length of it should be one now and the name of the first student should be Ron Weasley then test change teacher we're changing the teacher to SRA Snape and if you're a big Harry Potter fan like me you'll know SRA Snape always wanted to teach defense against the dark carts so I guess his dream has been fulfilled in this test and then we're setting the name to server Snape all right it looks pretty good so let's go ahead and copy that and back in our codebase let's create a new file in test we'll say testore school and here let's just paste all of it in and let's just correct our import so we need Source do school and let's go ahead and run this so I'm just going to increase this this clear it keeps doing that clear it again all right let's run this test so Pi tests and then test and test School run and we get an error because this did not raise to many students let's see let's go back and ask it so we'll say this let's copy this this test is is failing see what we get I apologize for the oversight no worries all right change this all right it's telling us to change the code that we're testing itself so maybe ah okay the issue is this is this less than and equals to so let's go back and yeah maybe that's correct so if the length of students is less than 10 now let's run this then we get All Passes all right so maybe you kind of have to shake chat GPT up a bit but this is US changing the code itself which I'm not a huge fan of so if we set that to equal to if the length of the students is equal to 10 then add a student and maybe actually this is actually our own error because we won only 10 students and so yeah I guess it kind of made us rethink that a bit but it's been quite useful so that's the free version that's chat GPT 3.5 let's go ahead and try it out on chat GPT 4 so I've gone ahead and selected chat GPT 4 I'm using the default one and this is the version that comes with the paid one so it's only exclusive plus users I definitely recommend it it's definitely worth the $20 if you have it as the value that you get out of it is just fantastic so I'm going to go ahead and paste in the exact same query so using p test and the functions that come from it such as fixtures paramed razors and Mark wherever necessary test the following code and theme after Harry Potter let's see what we get all right so so far it's somewhat similar so we got this students and this fixture is returning a list of students so herione Harry Ron Draco Malfoy Luna love good nille long botom wow so it's really added like a whole load of students to this so it's really understood Harry Potter I guess and then the class is Transfiguration class and it's setting mcgonagal as and if I remember correctly mle is the teacher for Transfiguration and this is a fixture for that ADD test add student so adding jinny Weasley add student and a certain new student is in the list of students okay very nice and then we have the too many students Transfiguration class new student Dean Thomas and raises too many students Transfiguration class add new student and then prati Patel and then test remove student and he's using parameterize here so student name Ron weaseling Draco Malfoy that's pretty cool and then change teacher so it's changing alist Moody to that okay let's actually go ahead and copy this and let's actually just count how many tests do we have we have 1 2 3 4 and five if you count the other parameterize so let's say four in our test school we have one two three four five five tests okay so not a huge difference let's go ahead and take all of this delete it and paste in our new one uh we just need to correct this so we'll say source. School let's go ahead and run that let's clear this and run it and we get an error and that is because it's still we never changed our students or like when we we gave it the prompt we never gave it the updated one so what we'll do is let's just quickly fix that and we'll give AI the benefit of the doubt so maybe we get rid of a student let's get rid of Sheamus finan no hate just that he was at the end of the list so let's run that again and there we go we have five passes so in all honesty I would say that the chat GPT 41 performed only slightly better only because we have this parameterized that comes with it and the naming is a bit better as well like it's stayed in line with the theme but that doesn't really matter in terms of tests just to like spice it up creatively but that brings us end to this tutorial we've now seen how AI can also be useful when it comes to writing test I definitely recommend it as it allows you to kind of catch the areas that you tend to miss when writing test so definitely make use of it but otherwise subscribe to free code Camp you can also contact me which is the my channel is in the description along with my Twitter but otherwise stay healthy stay safe and see you soon
Info
Channel: freeCodeCamp.org
Views: 168,081
Rating: undefined out of 5
Keywords:
Id: cHYq1MRoyI0
Channel Id: undefined
Length: 88min 38sec (5318 seconds)
Published: Mon Oct 23 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.