Intermediate Python Unit Testing
Transcript from the "Unit Testing" Lesson
>> Nina Zakharenko: There are a few different frameworks for writing them in Python, they're all pretty similar. But we're gonna focus on the one that comes with the standard library, it's pretty easy to remember, it's called unittest. unittest is both a framework for writing tests as well as a test runner.
[00:00:20] Meaning that you can use it to execute your test and return the results as well. In order to write unittest using this standard library, we need to write our test as methods within a class and we need to use a series of assertions that come in this unittest library not using the assert key word.
>> Nina Zakharenko: Okay, let's make a file here, I'm gonna call it multiply.py. Actually, I'm just gonna call it mult.py, keep me from having more typo errors. And I'm gonna define a function here called multiply. And it's gonna take an x and y and it's gonna return,
>> Nina Zakharenko: x times y.
[00:01:18] Okay, fair enough. Now let's write a test case for it. Usually, these tests are in a separate file, usually for larger projects, in a separate module called tests, so that you can cleanly break them up from your code base. But for this example, I'm just gonna put them right in this file, so, I'll say usually tests live in a test file, or module,
>> Nina Zakharenko: Not inline. And again, usually imports live at the top of the file but we're suspending our disbelief here. Some I'm gonna import the unittest library, and close my terminal there.
>> Nina Zakharenko: I'm going to import it at the top here because it's driving my nit pickiness crazy. So,
>> Nina Zakharenko: We need to write our tests in a separate class, and I'm gonna call this class TestMultiply. Calling it TestMultiply doesn't actually make it a unittest class, in order to do that we need to subclass from unittest.TestCase.
>> Nina Zakharenko: That signifies that this class contains a collection of unit tests.
[00:02:53] Now, let's write our very first unittest. Your unit test methods needs to start with test underscore, or they won't run they won't be picked up. And we are gonna pass in self here. And I'm gonna say the test value for x is 5 and the test value for y is 10.
[00:03:17] And we want to use the assertions provided to us by the unittest,
>> Nina Zakharenko: By the unit test class here. To find the fullest of assertions, take a look at the Python documentation, I'll make sure that there's a link to it in the class website. But until then there's kind of a few standard ones.
[00:03:39] And if you're using VS code and your interpreter is set up correctly, you'll actually get some helpful hints here. They all start with assert, which is great. If I wanna test assertEqual, I can even hit the,
>> Nina Zakharenko: If I call it without arguments, VS code will give me this little pop up, and it's gonna tell me that, what the arguments are, first, second.
[00:04:08] Message is a optional parameter here that we can pass in if we want to have our own custom error message when this fails. And we wanna fail if the two objects are unequal as determined by the equals operator, okay? So we're gonna call multiply,
>> Nina Zakharenko: With our test_x and our test_y, and,
>> Nina Zakharenko: This should equal 50, right?
>> Nina Zakharenko: If we just have a few simple unittests, we don't care about having something called a test runner. The test runner helps you discover tests in multiple directories. So I can just say if __name__ == " __main__ " put in some code and a main method here.
[00:05:02] So if I run this multiply, or mult.py file directly, I want to call the unittest.main method.
>> Nina Zakharenko: Okay, and let's run this. We'll see that it ran one test and the test was okay.
>> Nina Zakharenko: Let's introduce a bug into our code. I'm gonna change our multiply method to do addition instead.
[00:05:36] Now when I run this test, or run this file that has our test in it, it's gonna say failed. And the failures were one failure. Ran one test, and it failed one test.
>> Nina Zakharenko: If I provided a custom error message here that optional argument,
>> Nina Zakharenko: Should see a little bit more information there.
[00:06:08] So we got AssertionError 15 was not equal to 50, it should be 50, right? So this will help us catch bugs in our code. A few important concepts here, test case. The class must be a subclass your own test case must be a subclass of unittest.TestCase. The names of your functions must begin with test.
[00:06:34] And because these tests usually live in a separate test file or a module not in line, don't forget to import the code that you wanna test.
>> Nina Zakharenko: Okay, so running your test, one common way of doing it, we kinda saw, was using this.
>> Nina Zakharenko: Triggering unittest.main, if we're in our main context
>> Nina Zakharenko: If you skip this part,
>> Nina Zakharenko: The other way to run your unittest is to use that python -n flag. Remember, that's says Python run this next thing as a module. And you can pass in the name of unittest along with your test file. And it'll go and do the same thing even though I never said anywhere to explicitly run these tests.
>> Nina Zakharenko: When you're running your unitest with a -n unittest, you can also, it has to be after the -n. You can provide a -v flag. And if we look at our input now,
>> Nina Zakharenko: We'll see that our output was a lot verbose, instead of saying one test failed, now it shows us which test it was and which class it was in.