The difference between unittest and pytest

The difference between unittest and pytest

1. unittest

# MyFunction.py DEF the Add ( A, B ): return A + B duplicated code

1.1 unittest unit test

# Unit test.py """ 1. Unit testing framework: automatic verification results python:unittest or pytest, Java: Junit, TestNG How to write use cases: Must start with test Find use cases to parameterize """ import unittest import myFunction import HTMLTestRunner import HTMLTestRunnerNew # rich version of test report import parameterized # parameterized class TestAdd ( unittest.TestCase ): '''Test add method''' def testAddNormal1 ( self ): """Normal test addition, by huozi""" result = myFunction.add( 1 , 2 ) self.assertEqual( 3 , result,) def testAddNormal2 ( self ): """Normal test addition with msg return information """ result = myFunction.add( 4 , 2 ) self.assertEqual( 6 , result, 'normal case passed' ) def testAddError1 ( self ): """Used when the test fails, by huozi""" result = myFunction.add( 0 , 2 ) self.assertEqual( 4 , result) def testAddError2 ( self ): """The test failed. Use """ with msg return information result = myFunction.add( 1 , 2 ) self.assertEqual( 0 , result, 'normal integer addition, failed' ) @parameterized.parameterized.expand( # Passing parameters as a two-dimensional array [[ 1 , 2 , 3 , 'parameterized 1' ], [- 1 , 2 , 3 , 'parameterized 2' ], [ 2 , 4 , 7 , 'parameterized 3' ]] ) def testParamAdd ( self, a, b, c, desc ): self._testMethodDoc = desc # Use this _testMethodDoc parameter to pass result = myFunction.add(a, b) self.assertEqual(c, result, 'The expected result is %s, the actual result is %s' % (c, result)) if __name__ == ' __main__ ' : # Writing 0: No test report is generated # unittest.main() # Execute all use cases # Writing 1: Run a single test case testSuite1 = unittest.TestSuite() testSuite1.addTest(TestAdd( 'testAddNormal' )) # Run a single test case # testSuite.addTest(TestAdd('testAddError1')) # testSuite.addTest(TestAdd('testAddError1')) # Writing 2: Run test cases in a class testSuite2 = unittest.makeSuite(TestAdd) # Run all test cases in a class (such as TestAdd) # Writing method 3: Find the test case (absolute path) in a directory, the file must start with test, all files are: * .py testSuite3 = unittest.defaultTestLoader.discover( '/Users/ray/PycharmProjects/tmz/day9/cases' , 'test*.py' ) with open ( 'report.html' , 'wb' ) as fw: # runner = HTMLTestRunner.HTMLTestRunner(stream=fw, title=' ', description=' ',verbosity=3) runner = HTMLTestRunnerNew. HTMLTestRunner(stream=fw, title= 'Tianma Test Report' , description= 'Tianma Test' , verbosity= 3 ) runner.run(testSuite2) Copy code

2. pytest

2.1 pytest unit test

class TestClassOne ( Object ): DEF test_one ( Self ): X = "the this" Assert 'T' in X def test_two ( self ): x = "hello" assert hasattr (x, 'check' ) class TestClassTwo ( Object ): DEF test_one ( Self ): X = "iPhone" Assert 'P' in X DEF test_two ( Self ): X = "Apple" Assert the hasattr (X, 'Check' ) copying the code

3. The difference between unittest and pytest

3.1 Use case writing rules

Unittest provides test cases, test suites, test fixtures, and test runner related classes to make testing more clear, convenient and controllable. To write use cases using unittest, the following rules must be observed:

  1. The test file must first import unittest
  2. The test class must inherit unittest.TestCase
  3. The test method must start with "test_"
  4. The test class must have a unittest.main() method

pytest is a third-party testing framework for python, and is an extended framework based on unittest, which is more concise and more efficient than unittest. To write use cases using pytest, the following rules must be observed:

  1. The test file name must start with "test_" or end with "_test" (eg: test_ab.py)
  2. The test method must start with "test_".
  3. The test class name starts with "Test".

Summary: pytest can execute unittest-style test cases without modifying any code of the unittest case, which has better compatibility. There are rich pytest plug-ins, such as flask plug-ins, which can be used for error reruns of use cases; and xdist plug-ins, which can be used for device parallel execution.

3.2 Use case pre and post

  1. Unittest provides setUp/tearDown, which is run once before and after each use case is run. setUpClass and tearDownClass are only run once before and after the use case is executed.
# unittset preconditions.py import unittest class Test ( unittest.TestCase ): # Inherit the TestCase in unittest @classmethod def setUpClass ( cls ) -> None : # setUpClass: All use cases will be executed once before execution, such as: open the file and link to the database print ( 'setUpClass' ) @classmethod def tearDownClass ( cls ) -> None : # tearDownClass: All use cases will be executed once after execution, such as: delete data after registration print ( 'tearDownClass' ) @classmethod def setUp ( self ) -> None : # setUp: SetUp will be executed before each use case is executed, such as: print ( 'setUp' ) @classmethod def tearDown ( self ) -> None : # tearDown: tearDown will be executed first after each use case is executed, such as: print ( 'tearDown' ) def testB ( self ): # Use case execution order: start with the letter after test print ( 'testB' ) def testA ( self ): print ( 'testA' ) def testZ ( self ): print ( 'testZ' ) if __name__ == "__main__" : # unittest.main() # Do not generate test report pass Copy code

The results of its execution are as follows:

Ran 3 tests in 0.003s Launching unittests with arguments python -m unittest use case preconditions. Test in/Users/ray/PycharmProjects/day10 OK setUpClass tearDownClass Process finished with exit code 0 setUp testA tearDown setUp testB tearDown setUp testZ tearDown Copy code
  1. Pytest provides module-level, function-level, class-level, and method-level setup/teardown, which is more flexible than unittest's setUp/tearDown.
import pytest # Method in the module def setup_module (): print ( "setup_module: the entire .py module is executed only once" ) def teardown_module (): print ( "teardown_module: the entire test_module.py module is executed only once" ) def setup_function (): print ( "setup_function: will be executed before each use case starts" ) def teardown_function (): print ( "teardown_function: will be executed after each use case is over" ) # Use case 1 in the test module def test_one (): print ( "Executing the test module----test_one" ) x = "this" assert'h ' in x # Use case 2 in the test module def test_two (): print ( "Executing the test module----test_two" ) x = "hello" assert hasattr (x, 'check' ) # Test class class TestCase (): def setup_class ( self ): print ( "setup_class: before all use cases are executed" ) def teardown_class ( self ): print ( "teardown_class: After all use cases are executed" ) def setup ( self ): print ( "setup: will be executed before each use case starts" ) def teardown ( self ): print ( "teardown: will be executed after each use case is over" ) def test_three ( self ): print ( "Executing test class----test_three" ) x = "this" assert'h ' in x def test_four ( self ): print ( "Executing test class----test_four" ) x = "hello" assert hasattr (x, 'check' ) if __name__ == "__main__" : pytest.main([ "-s" , "test_module.py" ]) Copy code

The results of its execution are as follows:

collected 4 items test_module.py setup_module: The entire .py module is executed only once setup_function: will be executed before each use case starts Executing test module----test_one .teardown_function: will be executed after each use case is over setup_function: will be executed before each use case starts Executing test module----test_two Fteardown_function: will be executed after each use case is over setup_class: before all use cases are executed setup: will be executed before each use case starts Executing test class----test_three .teardown: will be executed after each use case is over setup: will be executed before each use case starts The test class is being executed----test_four Fteardown: will be executed after each use case is over teardown_class: After all use cases are executed teardown_module: The entire test_module.py module is executed only once Copy code

Method 2: fixture

# conftest.py # -*- coding: utf-8 -*- import pytest @pytest.fixture( scope= "function" ) def login (): print ( "Please enter your account and password first, then log in" ) yield Print ( "logout" ) Copy the code
# test_1.py # -*- coding: utf-8 -*- import pytest def test_fix1 ( login ): print ( "test_fix1 in test_1.py: need to log in and then perform the operation" ) def test_fix2 (): print ( "test_fix2 in test_1.py: do not need to log in to perform the operation" ) def test_fix3 ( login ): print ( "test_fix3 in test_1.py: need to log in and then perform the operation" ) if __name__ == "__main__" : pytest.main ([ '-s' , 'test_1.py' ]) Copy the code
# test_2.py # -*- coding: utf-8 -*- import pytest def test_fix3 (): print ( "test_fix3 in test_2.py: do not need to log in to perform the operation" ) def test_fix4 ( login ): print ( "test_fix4 in test_2.py: need to log in and then perform the operation" ) if __name__ == "__main__" : pytest.main ([ '-s' , 'test_2.py' ]) Copy the code

The results of its execution are as follows:

pytest -s test_1.py collected 3 items test_1.py Please enter the account and password first, and then log in test_fix1 in test_1.py: need to log in and then perform the operation .sign out test_fix2 in test_1.py: do not need to log in to perform the operation .Please enter your account and password first, and then log in test_fix3 in test_1.py: need to log in and then perform the operation .sign out Copy code

3.3 Assertions

  1. Unittest provides assertEqual, assertIn, assertTrue, and assertFalse.

assertEqual: Determine whether the first parameter and the second parameter are equal, if they are not equal, the test fails

Usage: assertIn(key, container, message)

  • key: A string to check for existence in a given container
  • container: the string in which to search for the key string
  • message: A character string statement that is displayed when the test message fails.

assertIn: Used in unit tests to check whether the string is contained in other strings. This function will use three string parameters as input and return a Boolean value based on the assertion condition. If the key is contained in the container string, it will return true, otherwise it will return false.

Usage: assertIn(key, container, message)

Parameters: assertIn() accepts the description of the following three parameters:

  • key: A string to check for existence in a given container
  • container: the string in which to search for the key string
  • message: A character string statement that is displayed when the test message fails.

assertTrue: Determine whether it is true

assertFalse: Determine whether it is false

  1. pytest directly uses assert expressions.

assert: Used to judge an expression and trigger an exception when the expression condition is false.

3.4 Report

  1. unittest uses the HTMLTestRunnerNew library.
  2. pytest has pytest-HTML and allure plugins.

3.5 Rerun after failure

  1. Unittest does not have this function.
  2. pytest supports rerun after use case execution failure, pytest-rerunfailures plugin.

3.6 Parameterization

  1. Unittest depends on either the ddt library or the parameterized library.
  2. pytest directly uses the @pytest.mark.parametrize decorator.

3.7 Use case classification execution

  1. Unittest executes all test cases by default, and some module test cases can be executed by loading testsuite;
  2. Pytest can mark test cases through @pytest.mark, and execute the command plus the parameter "-m" to run the marked use cases.