This article mainly introduces the Python unit test, the code is based on the python2.x version, the need friend may refer to the next
If you've ever heard of "test-driven Development" (Tdd:test-driven Development), unit testing is not unfamiliar.
Unit tests are tests that are used to test the correctness of a module, a function, or a class.
For example, for the function abs (), we can write the following test cases:
Enter positive numbers, such as 1, 1.2, and 0.99, expecting the return value to be the same as the input;
Enter negative numbers, such as-1,-1.2,-0.99, expecting the return value to be the opposite of the input;
Enter 0 and expect to return 0;
Enter non-numeric types, such as none, [], {}, expecting to throw typeerror.
Putting the test case above into a test module is a complete unit test.
If the unit test passes, it means that the function we are testing is working correctly. If a unit test does not pass, either the function has a bug, or the test condition is entered incorrectly, in short, a fix is needed to allow the unit test to pass.
What does a unit test mean after it's passed? If we modify the ABS () function code, only need to run again unit test, if passed, that our changes will not affect the ABS () function of the original behavior, if the test does not pass, that our changes and the original behavior is inconsistent, or modify the code, Either modify the test.
The biggest benefit of this test-driven development model is to ensure that the behavior of a program module conforms to the test case that we designed. The behavior of the module can be guaranteed to be correct in the future when it is modified.
Let's write a dict class that behaves like a dict, but can be accessed through attributes, as follows:
?
1 2 3 4 5 |
>>> d = Dict (A=1, b=2) >>> d[' a '] 1 >>> d.a 1 |
The mydict.py code is as follows:
?
1 2 3 4 5 6 7 8 9 10 11 12-13 |
Class Dict (Dict): Def __init__ (self, **kw): Super (Dict, self). __init__ (**KW) def __getattr__ (self, key): Try:return s Elf[key] except Keyerror:raise attributeerror (r "' Dict ' object has no attribute '%s '"% key) def __setattr__ (self, key, Value): Self[key] = value |
In order to write unit tests, we need to introduce Python's own unittest module to write mydict_test.py as follows:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
Import unittest from mydict Import Dict class Testdict (unittest. TestCase): def test_init (self): D = Dict (a=1, b= ' test ') self.assertequals (D.A, 1) self.assertequals (d.b, ' test ') self.as Serttrue (Isinstance (d, Dict)) def test_key (self): D = dict () d[' key ' = ' value ' self.assertequals (D.key, ' value ') def Test_attr (self): D = Dict () D.key = ' value ' self.asserttrue (' key ' in D) self.assertequals (d[' key '], ' value ') def Test_ke Yerror (self): D = Dict () with Self.assertraises (keyerror): value = d[' empty '] def test_attrerror (self): D = Dict () with Self.assertraises (attributeerror): value = D.empty |
When writing unit tests, we need to write a test class from UnitTest. TestCase inheritance.
The method that begins with test is a method of testing, and a method that does not begin with test is not considered a test method and is not executed when it is tested.
You need to write a test_xxx () method for each type of test. Due to unittest. TestCase provides a lot of built-in conditional judgments, and we just need to call these methods to assert that the output is what we expect. The most common assertion is assertequals ():
Self.assertequals (ABS (-1), 1) # assertion function returns the same result as 1
Another important assertion is that the assertion throws a keyerror when it expects to throw a specified type of error, such as accessing a nonexistent key via d[' empty ':
?
1 2 |
With Self.assertraises (keyerror): value = d[' Empty '] |
And by D.empty access to nonexistent key, we expect to throw Attributeerror:
?
1 2 |
With Self.assertraises (attributeerror): value = D.empty |
Run unit Tests
Once the unit tests have been written, we can run the unit tests. The simplest way to run it is to add two lines of code at the end of the mydict_test.py:
?
1 2 |
if __name__ = = ' __main__ ': Unittest.main () |
This allows you to run mydict_test.py as a normal Python script:
?
1 |
$ python mydict_test.py |
Another more common approach is to run unit tests directly on the command line by using the parameter-M unittest:
?
1 2 3 4 5 6 |
$ python-m unittest mydict_test ...----------------------------------------------------------------------Ran 5 Tests in 0.000s OK |
This is a recommended practice because it allows you to run many unit tests at once, and there are a number of tools that can automatically run these unit tests.
Setup and teardown
You can write two special setup () and teardown () methods in a unit test. The two methods are executed separately before and after each call to a test method.
What's the use of the setup () and teardown () methods? Imagine that your test needs to start a database, at which point you can connect to the database in the Setup () method and shut down the database in the teardown () method so that you do not have to repeat the same code in each test method:
?
1 2 3 4 5 6 7 |
Class Testdict (UnitTest. TestCase): def setUp (self): print ' Setup ... ' def teardown (self): print ' teardown ... ' |
You can run the test again to see if the setup will print out before and after each test method call ... and teardown ....
Summary
Unit test can effectively test the behavior of a program module, is the confidence guarantee of future refactoring code.
Test cases for unit tests cover commonly used input combinations, boundary conditions, and exceptions.
Unit test code is very simple, if the test code is too complex, then the test code itself may have bugs.
The unit test passed does not mean that the program has no bugs, but there must be bugs without the program.