Python unit testing framework series: unit testing framework Python talk of (a): the unittest


Author: HelloGitHub- Prodesire

HelloGitHub of "explain open source projects" series, Project address: https: //github.com/HelloGitHub-Team/Article

Foreword

When it comes to Python unit testing framework, presumably exposed to Python friends head first thought is unittest .
Indeed, as the Python standard library, which is very good, and is widely used in various projects. But you know what? In fact, many Python projects, mainstream unit testing framework much more than this one.

This series of articles will introduce the popular unit testing framework for Python, talk about their functions and features and compare their similarities and differences, in order to let everyone in the face of different scenarios, different needs of the time, be able to balance, to choose the best unit testing framework.

本文默认以 Python 3 为例进行介绍,若某些特性在 Python 2 中没有或不同,会特别说明。

I. INTRODUCTION

unittest Unit testing framework inspired by JUnit the earliest, unit testing framework and other mainstream languages have similar style.

It supports test automation, a plurality of pre-shared test (the setUp) and clean (the tearDown) codes, a plurality of test cases to test a polymerization concentration, and the test and independent reporting framework.

Second, prepared by Example

The following simple example of this comes from official documents , to test three kinds of string methods: upper, isupper, split:

import unittest

class TestStringMethods(unittest.TestCase):

    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

    def test_isupper(self):
        self.assertTrue('FOO'.isupper())
        self.assertFalse('Foo'.isupper())

    def test_split(self):
        s = 'hello world'
        self.assertEqual(s.split(), ['hello', 'world'])
        # check that s.split fails when the separator is not a string
        with self.assertRaises(TypeError):
            s.split(2)

if __name__ == '__main__':
    unittest.main()

The above example, through inheritance unittest.TestCase to create a test case.
In this class, defined in testthe method, the beginning of the test frame will be used as an independent test to perform.

Each use case use unittestif the built-assertion method to determine the measured object behavior is expected, for example:

  • In test_uppertests, assertEqual check whether the expected value
  • In test_isuppertests, assertTrue or assertFalse verify compliance with the conditions
  • In test_splittests, assertRaises verify throw a particular exception

Some may wonder, why not use the built-assertion assert, and to provide so much additional assertion methods and the use of it? The reason is that by using the unittestassertion methods provided by the testing framework at the end of the run, all test results can be aggregated to generate a wealth of information and test reports. The direct use assert, although you can also achieve the purpose of verifying whether the measured object in line with expectations, but the use case when an error occurs, the error message is not rich.

Third, execution and use were found

unittest Automatic support (recursively) found with Example:

  • The default directory found all in line with the current test*.pytest case
    • Use python -m unittestorpython -m unittest discover
  • By -s, catalog parameter specifies automatic discovery -pparameter specifies the name of the file cases with the Mode
    • python -m unittest discover -s project_directory -p "test_*.py"
  • Automatic discovery directory specified by the position parameter and the file with the name pattern Example
    • python -m unittest discover project_directory "test_*.py"

unittest Support the implementation of the specified use cases:

  • Specifies the test module
    • python -m unittest test_module1 test_module2
  • Specify the test class
    • python -m unittest test_module.TestClass
  • Specify test methods
    • python -m unittest test_module.TestClass.test_method
  • Specifies the test file path (only Python 3)
    • python -m unittest tests/test_something.py

Fourth, the test fixture (Fixtures)

The test fixture is pre-test (setUp) and clean (tearDown) method.

Pre-test method setUp () to do some preparatory work, such as establishing a database connection. It will automatically be called before the implementation of the use case testing framework.

Test Methods for cleaning up tearDown () to do some cleanup work, such disconnect from the database. It will complete execution using embodiment (including the case of failure) after the test frame is automatically invoked.

Pre-testing and clean-up methods can have different execution level.

4.1 take effect level: test methods

If we want before each test method before and after each test is performed pre- and clean-up methods, you need to define the test class setUp () and tearDown () :

class MyTestCase(unittest.TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        pass

4.2 take effect level: class test

If we want a single test class only once before methods, and then perform all tests in the test class, and finally perform a cleanup method, you need to define the test class setUpClass () and tearDownClass () :

class MyTestCase(unittest.TestCase):
    def setUpClass(self):
        pass

    def tearDownClass(self):
        pass

4.3 take effect level: test module

If we want a single test module is executed only once before methods, then execute the test module in all tests for all classes, and finally perform a cleanup method, you need to define the test module setUpModule () and tearDownModule () :

def setUpModule():
    pass

def tearDownModule():
    pass

Fifth, and is expected to skip the test fails

unittest Support skip or skip the conditional test, also is expected to support the test fails:

class MyTestCase(unittest.TestCase):

    @unittest.skip("直接跳过")
    def test_nothing(self):
        self.fail("shouldn't happen")

    @unittest.skipIf(mylib.__version__ < (1, 3),
                     "满足条件跳过")
    def test_format(self):
        # Tests that work for only a certain version of the library.
        pass

    @unittest.skipUnless(sys.platform.startswith("win"), "满足条件不跳过")
    def test_windows_support(self):
        # windows specific testing code
        pass

    def test_maybe_skipped(self):
        if not external_resource_available():
            self.skipTest("跳过")
        # test code that depends on the external resource
        pass

    @unittest.expectedFailure
    def test_fail(self):
        self.assertEqual(1, 0, "这个目前是失败的")

Six subtests

Sometimes, you might want to write such a test: passed different parameters in a test method for testing the same period of logic, but it will be considered a test, but if the child test , can be regarded as N ( is the number of parameters) test. Here is an example:

class NumbersTest(unittest.TestCase):

    def test_even(self):
        """
        Test that numbers between 0 and 5 are all even.
        """
        for i in range(0, 6):
            with self.subTest(i=i):
                self.assertEqual(i % 2, 0)

Used in the example with self.subTest(i=i)of subtests define, in this case, even a single sub-test fails, it will not affect the execution of subsequent sub-tests. In this way, we can see the output has three sub-tests do not pass:

======================================================================
FAIL: test_even (__main__.NumbersTest) (i=1)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "subtests.py", line 32, in test_even
    self.assertEqual(i % 2, 0)
AssertionError: 1 != 0

======================================================================
FAIL: test_even (__main__.NumbersTest) (i=3)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "subtests.py", line 32, in test_even
    self.assertEqual(i % 2, 0)
AssertionError: 1 != 0

======================================================================
FAIL: test_even (__main__.NumbersTest) (i=5)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "subtests.py", line 32, in test_even
    self.assertEqual(i % 2, 0)
AssertionError: 1 != 0

Seven test result output

A simple example based on the example mentioned in section, to illustrate the unittestoutput result of the test run to completion.

Output very simple case of default, the show runs a number of use cases, as well as the time it takes:

...
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

By specifying -vparameters, you can be output in detail, in addition to the contents of the default output, and additionally shows the use Name Example:

test_isupper (__main__.TestStringMethods) ... ok
test_split (__main__.TestStringMethods) ... ok
test_upper (__main__.TestStringMethods) ... ok

----------------------------------------------------------------------
Ran 3 tests in 0.001s

OK

Assumed that test_upperthe test fails, the output mode in detail, the following results:

test_isupper (tests.test.TestStringMethods) ... ok
test_split (tests.test.TestStringMethods) ... ok
test_upper (tests.test.TestStringMethods) ... FAIL

======================================================================
FAIL: test_upper (tests.test.TestStringMethods)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Uvsers/prodesire/projects/tests/test.py", line 6, in test_upper
    self.assertEqual('foo'.upper(), 'FOO1')
AssertionError: 'FOO' != 'FOO1'
- FOO
+ FOO1
?    +


----------------------------------------------------------------------
Ran 3 tests in 0.001s

FAILED (failures=1)

If we test_uppertest method self.assertEqualwas changed assert, then the test results output will be less context information to troubleshoot errors helpful:

test_isupper (tests.test.TestStringMethods) ... ok
test_split (tests.test.TestStringMethods) ... ok
test_upper (tests.test.TestStringMethods) ... FAIL

======================================================================
FAIL: test_upper (tests.test.TestStringMethods)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/prodesire/projects/tests/test.py", line 6, in test_upper
    assert 'foo'.upper() == 'FOO1'
AssertionError

----------------------------------------------------------------------
Ran 3 tests in 0.001s

FAILED (failures=1)

If you want to generate a report in HTML format, you need extra help third-party libraries (such as HtmlTestRunner ) to operate.

After installing third-party libraries, you can not directly python -m unittestadd a similar --html report.htmlway to generate HTML reports, but a small amount of code you need to write their own test cases to run and then get an HTML report.
For details, see HtmlTestRunner instructions .

VIII Summary

unittest unit testing framework as the Python standard library provides a simple to use, powerful, routine testing requirements can be well satisfied. Without the introduction of third-party libraries, unit testing is the best choice.

In the next article, we will introduce a third-party unit test framework noseand nose2, in contrast to talk about it unittestimproves on that so many developers prefer it.

Public concern number to join the exchange group, to discuss interesting topics with technology

Guess you like

Origin www.cnblogs.com/xueweihan/p/11494418.html