One, what is unit test
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 test cases as:
(1) Enter positive numbers, such as 1, 1.2, 0.99, and expect the return value to be the same as the input
(2) Enter complex numbers, such as-1,-1.2,-0.99, expecting the return value to be the opposite of the input
(3) input 0, expect to return 0
(4) Input non-numeric type, such as none, [], {}, expecting to throw TypeError
Putting these test cases into a test module is a complete unit test
Second,unittest working principle
The core four parts of UnitTest are: testcase,testsuite,testrunner,testfixture
(1) An example of a testcase is a test case. A test case is a complete test process that includes the setup of the preparation environment before the test, the execution of the test code (run), and the restoration of the environment after the test (teardown). The nature of the Meta Test (unit test) is right here, a test case is a complete test cell, by running the test unit, you can verify a problem.
(2) While multiple test cases are assembled, they are testsuite, and testsuite can also be nested testsuite.
(3) Testloader is used to load testcase into the testsuite.
(4) Texttestrunner is to execute the test case, where run (test) executes the run (Result) method in Testsuite/testcase
(5) The results of the test will be saved to the Texttestresult instance, including how many test cases have been run, how much has been accomplished, and how much has failed.
In summary, the whole process is the first to write a good testcase, and then by Testloader loaded testcase to Testsuite, and then run Texttestrunner by Testsuite, the results of the operation saved in the Texttestresult , the whole process is integrated into the Unittest.main module.
three, two examples below to see how unittest test a simple function
(1) Write a dict class that behaves like a dict, but can be accessed by attributes such as
>>> d = Dict (A=1, b=2)
>>> d[' A ']
1
>>> d.a
1
The mydict.py code is as follows:
Class Dict (Dict):
def __init__ (self, **kw):
super (Dict, self). __init__ (**kw)
def __getattr__ (self, key):
try: Return
Self[key]
except Keyerror:
raise Attributeerror (r "' Dict ' object has no attribute '%s '"% Key)
def __setattr__ (self, Key, value):
Self[key] = value
The file mydict_test.py code for the test is as follows:
Import unittest from
mydict import Dict
class Testdict (unittest. TestCase):
def test_init (self):
d = Dict (a=1, b= ' test ')
self.assertequal (D.A, 1) # to determine if D.A equals 1
Self.assertequal (d.b, ' test ') # to determine if the d.b equals test
self.asserttrue (isinstance (d, Dict)) # to determine if D is a dict type
def test_key (self):
d = Dict ()
d[' key ' = ' value '
self.assertequal (d.key, ' value ')
def test _attr (self):
d = Dict ()
D.key = ' value '
self.asserttrue (' key ' in D)
self.assertequal (d[' key '), ' Value ')
def test_keyerror (self):
d = Dict ()
with Self.assertraises (keyerror): # through d[' empty '] When accessing a key that does not exist, the assertion throws Keyerror
value = d[' empty '
def test_attrerror (self):
d = Dict ()
with Self.assertraises (Attributeerror): # When accessing nonexistent key via D.empty, we expect to throw attributeerror
value = D.empty
if __ name__ = = ' __main__ ':
unittest.main ()
Just run mydict_test.py as a normal Python script.
Output:
.....
----------------------------------------------------------------------
Ran 5 tests in 0.000s
OK
(2) to measure a simple subtraction interface
The mathfunc.py file code is as follows:
def add (A, B): return
A + b
def minus (A, b): Return
a-b
def multi (A, B): Return
A * b
def divide (A, B): return
B
The test_mathfunc.py file code is as follows:
Import unittest from
mathfunc Import *
class Testmathfunc (unittest. TestCase):
def test_add (self):
self.assertequal (3, Add (1, 2))
self.assertnotequal (3, Add (2, 2))
def Test_minus (self):
self.assertequal (1, minus (3, 2))
def test_multi (self):
self.assertequal (6, multi (3, 2 )
def test_divide (self):
self.assertequal (2, Divide (6, 3))
self.assertequal (2.5, Divide (5, 2))
if __name__ = = ' __main__ ':
unittest.main ()
Output:
. F..
======================================================================
fail:test_divide (__main__. testdict)
----------------------------------------------------------------------
Traceback (most recent Call last):
File "d:/pythonworkspace/test_mathfunc.py", line, in Test_divide
self.assertequal (2.5, divide ( 5, 2))
assertionerror:2.5!= 2
----------------------------------------------------------------------
Ran 4 tests in 0.000s
FAILED (Failures=1)
You can see that you ran 4 tests, failed 1, and gave the reason for failure, 2.5!=2, which means our divide method is problematic.
A few notes on the output:
1, in the first line gives the identification of the results of each use case execution, success is., failure is F, error is E, skip is S. As you can see from the above, the execution of the test has nothing to do with the order of the methods, the Divide method is written in the 4th, but it is executed at the 2nd.
2, each test method starts with test, otherwise cannot be unittest recognized
3, in Uniitest.main () with the verbosity parameter can control the output error report of the level of detail, the default is 1, if set to 0, do not output the execution result of each use case, that is, no 1th row in the above result, if set to 2, then output detailed execution results, as follows:
Test_add (__main__. Testmathfunc) ... ok
test_divide (__main__). Testmathfunc) ... FAIL
Test_minus (__main__. Testmathfunc) ... ok
test_multi (__main__). Testmathfunc) ... ok
======================================================================
fail:test_ Divide (__main__. Testmathfunc)
----------------------------------------------------------------------
traceback (most Recent call last):
File "d:/pythonworkspace/test_mathfunc.py", line, in Test_divide
self.assertequal (2.5, Divide (5, 2))
assertionerror:2.5!= 2
------------------------------------------------------------------ ----
Ran 4 tests in 0.000s
FAILED (Failures=1)
Four, Organization Testsuite
The test cases above are not executed sequentially, and testsuite is used if you want the use cases to be executed in the order you set them. The case we add to the testsuite is executed in the order in which they were added.
Now we have only one test file, and if we have multiple test files, we can organize them with testsuite.
To continue with the example of the second subtraction above, now create a new file, test_suite.py, the following code:
# coding=utf-8
import unittest from
test_mathfunc import testmathfunc
if __name__ = ' __main__ ':
Suite = UnitTest. TestSuite ()
tests = [Testmathfunc ("Test_add"), Testmathfunc ("Test_minus"), Testmathfunc ("Test_divide")]
Suite.addtests (Tests)
runner = UnitTest. Texttestrunner (verbosity=2)
Runner.run (Suite)
The results of the implementation are as follows:
Test_add (Test_mathfunc. Testmathfunc) ... ok
test_minus (test_mathfunc). Testmathfunc) ... ok
test_divide (test_mathfunc). Testmathfunc) ... FAIL
======================================================================
fail:test_divide (test_ Mathfunc. Testmathfunc)
----------------------------------------------------------------------
traceback (most Recent call last):
File "D:\pythonWorkspace\HTMLTest\test_mathfunc.py", line, in Test_divide
Self.assertequal (2.5, Divide (5, 2))
assertionerror:2.5!= 2
---------------------------------------------- ------------------------
Ran 3 tests in 0.000s
FAILED (Failures=1)
Five, output the results to a file
Now our test results can only be exported to the console, and now we want to output the results to the file for subsequent viewing.
Make a little change to the test_suite.py code as follows:
# coding=utf-8
import unittest from
test_mathfunc import testmathfunc
if __name__ = ' __main__ ':
Suite = UnitTest. TestSuite ()
tests = [Testmathfunc ("Test_add"), Testmathfunc ("Test_minus"), Testmathfunc ("Test_divide")]
Suite.addtests (Tests)
with open (' UnittestTextReport.txt ', ' a ') as f:
runner = UnitTest. Texttestrunner (Stream=f, verbosity=2)
Runner.run (Suite)
Running the file, you will find that the directory generates ' UnittestTextReport.txt, and all the execution reports are exported to this file.
the setup and teardown of test fixture
When you encounter the situation where you want to start a database, you only want to connect to the database at the beginning and close the connection at the end. Then you can use the setup and teardown functions.
Class Testdict (UnitTest. TestCase):
def setUp (self):
print ' Setup ... '
def teardown (self):
print ' teardown ... '
The two methods are executed before each test method executes and after execution, and setup is used to prepare the environment for the test, teardown to clean up the environment for subsequent tests.
If you want to prepare an environment before all case execution and then clean up the environment after all case execution is finished, we can use SetupClass () and Teardownclass () with the following code format:
Class Testmathfunc (UnitTest. TestCase):
@classmethod
def setupclass (CLS):
print "SetUp"
@classmethod
def teardownclass (CLS ):
print "teardown"
Seven, Skip a case
UnitTest offers several ways to skip case
(1)Skip decoration device
The code is as follows
# coding=utf-8
import unittest from
mathfunc Import *
class Testmathfunc (unittest. TestCase): ...
@unittest. Skip ("I don ' t want to run this case.")
def test_minus (self):
self.assertequal (1, minus (3, 2))
Output:
Test_add (Test_mathfunc. Testmathfunc) ... ok
test_minus (test_mathfunc). Testmathfunc) ... skipped "I don ' t want to run this case."
Test_divide (Test_mathfunc. Testmathfunc) ... FAIL
======================================================================
fail:test_divide (test_ Mathfunc. Testmathfunc)
----------------------------------------------------------------------
traceback (most Recent call last):
File "D:\pythonWorkspace\HTMLTest\test_mathfunc.py", line, in Test_divide
Self.assertequal (2.5, Divide (5, 2))
assertionerror:2.5!= 2
---------------------------------------------- ------------------------
Ran 3 tests in 0.000s
FAILED (Failures=1, skipped=1)
There are three skip adorners
Unittest,skip (reason): Skip unconditionally
UNITTEST.SKIPIF (condition, reason): skipping when condition is true
Unittest.skipunless (condition, reason): skipping when condition is false
(2) testcase.skiptest () method
Class Testmathfunc (UnitTest. TestCase): ...
def test_minus (self):
self.skiptest (' Don't run this. ')
Self.assertequal (1, minus (3, 2))
Output:
Test_add (Test_mathfunc. Testmathfunc) ... ok
test_minus (test_mathfunc). Testmathfunc) ... skipped ' don't run this. '
Test_divide (Test_mathfunc. Testmathfunc) ... FAIL
======================================================================
fail:test_divide (test_ Mathfunc. Testmathfunc)
----------------------------------------------------------------------
traceback (most Recent call last):
File "D:\pythonWorkspace\HTMLTest\test_mathfunc.py", line, in Test_divide
Self.assertequal (2.5, Divide (5, 2))
assertionerror:2.5!= 2
---------------------------------------------- ------------------------
Ran 3 tests in 0.000s
FAILED (Failures=1, skipped=1)
Eight, use Htmltestrunner to output beautiful HTML reports
TXT format Text execution report too shabby, here we learn to generate HTML reports with the help of Htmltestrunner. First you need to download htmltestrunner.py, and put it in the current directory, or in the Python directory in the LIB, you can import the run.
Download Address: http://tungwaiyip.info/software/HTMLTestRunner.html
Modify the test_suite.py code as follows:
# coding=utf-8
import unittest from
test_mathfunc import testmathfunc from
htmltestrunner Import Htmltestrunner
If __name__ = = ' __main__ ':
suite = UnitTest. TestSuite ()
tests = [Testmathfunc ("Test_add"), Testmathfunc ("Test_minus"), Testmathfunc ("Test_divide")]
Suite.addtests (Tests)
with open (' htmlreport.html ', ' W ') as F:
runner = Htmltestrunner (stream=f,
title = ' Mathfunc Test ",
description= ' generated by Htmltestrunner. ',
verbosity=2
)
Runner.run ( Suite
After execution, the console output is as follows:
Ok Test_add (Test_mathfunc. Testmathfunc)
F test_divide (test_mathfunc. Testmathfunc) Time
elapsed:0:00:00.001000
Generated HTML:
IX, Summary
1. UnitTest is a Python self-contained unit test framework that we can use as a framework for implementing use-case organizations for our automated test framework.
2, UnitTest process: Write good testcase, then by Testloader load TestCase to Testsuite, and then run Texttestrunner by Testsuite, The result of the run is saved in Texttestresult, and when we execute it through the command line or Unittest.main (), main will invoke run in Texttestrunner to execute, Or we can execute the use case directly through Texttestrunner.
3, a class inherits UnitTest. TestCase is a testcase in which the method that begins with test is loaded as a real testcase at load time.
4, the verbosity parameter can control the output of the execution result, 0 is the simple report, 1 is the general report, 2 is the detailed report.
5, you can add case or suite to the suite through Addtest and addtests, you can use the Testloader loadtestsfrom__ () method.
6. Use SetUp (), teardown (), SetupClass (), and Teardownclass () to lay out the environment before the use case is performed, and to clean up the environment after use case execution
7, we can skip a case through the skip,skipif,skipunless adorner, or use the Testcase.skiptest method.
8, the parameter adds stream, can output the report to the file: can use Texttestrunner output TXT report, and can use Htmltestrunner output HTML report.