Python module - unittest framework unittest

1. Quick start

1. Introduction to unittest

unittest is a built-in unit testing framework in Python, which can be called directly without installation. Some of the core concepts are as follows:
Test Fixture:

  • Test scaffolding is used to complete test pre-processing and post-processing. For example, the environment is prepared before the test, and the environment is destroyed after the test is completed.
  • Test function level: setUp, tearDown
  • Test class level: setUpClass, tearDownClass

Test Case:

  • Test case, a test case is an independent test unit, and new test cases need to inherit unittest.TestCase.

Test Suite:

  • Test suites, used to collect test cases or test suites. suite = unittest.TestSuite()

Test Loader:

  • Test loader, used to load test cases into the test suite. unittest. TestLoader()

Test Runner:

  • A test runner that runs tests and outputs test results. For example, output the test results in text format: unittest.TextTestRunner()

2. Write test cases

To create a new test case, you need to inherit unittest.TestCase. The test case starts with test*, and a test case is written for each unit.

  1. Write the test case TestCase1.py as follows:
import unittest


class TestCase1(unittest.TestCase):
    @classmethod
    def setUpClass(cls) -> None:
        print('setUpClass...')

    def setUp(self) -> None:
        print('setUp...')

    def test1(self):
        print('test1...')

    def test2(self):
        print('test2...')

    def tearDown(self) -> None:
        print('tearDown...')

    @classmethod
    def tearDownClass(cls) -> None:
        print('tearDownClass...')


class TestCase2(unittest.TestCase):
    @classmethod
    def setUpClass(cls) -> None:
        print('setUpClass...')

    def setUp(self) -> None:
        print('setUp...')

    def test1(self):
        print('test3...')

    def test2(self):
        print('test4...')

    def tearDown(self) -> None:
        print('tearDown...')

    @classmethod
    def tearDownClass(cls) -> None:
        print('tearDownClass...')

  1. Write the test case TestCase2.py as follows:
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
from BeautifulReport import BeautifulReport


class TestCase(unittest.TestCase):
    driver = None

    @classmethod
    def setUpClass(cls) -> None:
        cls.driver = webdriver.Chrome()
        cls.driver.get('https://www.baidu.com')
        cls.driver.maximize_window()

    @BeautifulReport.add_test_img('搜索前', '搜索后')
    def test(self):
        """测试百度搜索"""
        self.driver.save_screenshot('img/搜索前.png')
        self.driver.find_element(By.ID, 'kw').send_keys('selenium')
        self.driver.find_element(By.ID, 'su').click()
        WebDriverWait(self.driver, 10).until(expected_conditions.title_contains('selenium'), '等待搜索结果超时!!!')
        self.driver.save_screenshot('img/搜索后.png')

    @classmethod
    def tearDownClass(cls) -> None:
        cls.driver.quit()

3. Use the test suite to load test cases

The methods of the test suite TestSuite object include addTest to load test cases (test suites) one by one, and addTests to load multiple test cases (test suites). It can also be used in conjunction with the method of the TestLoader object of the test loader to load multiple test cases.

import unittest
import TestCase1


# 逐个加载测试用例
def suite1():
    # 实例化测试套件
    testsuite = unittest.TestSuite()
    # 加载测试用例到测试套件
    testsuite.addTest(TestCase1.TestCase1('test1'))
    testsuite.addTest(TestCase1.TestCase1('test2'))

    return testsuite


# 加载多个测试用例
def suite2():
    # 实例化测试套件
    testsuite = unittest.TestSuite()
    # 加载测试用例到测试套件
    cases = [TestCase1.TestCase2('test3'), TestCase1.TestCase2('test4')]
    testsuite.addTests(cases)

    return testsuite


# 逐个加载测试套件
def suite3():
    # 实例化测试套件
    testsuite = unittest.TestSuite()
    # 加载测试套件到测试套件
    testsuite.addTest(suite1())
    testsuite.addTest(suite2())

    return testsuite


# 加载多个测试套件
def suite4():
    # 实例化测试套件
    testsuite = unittest.TestSuite()
    # 加载测试套件到测试套件
    suites = [suite1(), suite2()]
    testsuite.addTests(suites)

    return testsuite


# TestLoader() 测试加载器
# loadTestsFromTestCase(testCaseClass) 加载某个测试类中的所有测试用例
def suite5():
    # 实例化测试套件
    testsuite = unittest.TestSuite()
    # 实例化测试加载器
    loader = unittest.TestLoader()
    # 加载某个测试类中的所有测试用例
    testsuite.addTest(loader.loadTestsFromTestCase(TestCase1.TestCase1))

    return testsuite


# loadTestsFromModule(module) 加载某个模块中的所有测试用例
def suite6():
    # 实例化测试套件
    testsuite = unittest.TestSuite()
    # 实例化测试加载器
    loader = unittest.TestLoader()
    # 加载某个模块中的所有测试用例
    testsuite.addTest(loader.loadTestsFromModule(TestCase1))

    return testsuite


# loadTestsFromName(name) 根据指定的字符串加载测试用例,字符串可以是模块名、测试类名、测试类中的测试方法名
def suite7():
    # 实例化测试套件
    testsuite = unittest.TestSuite()
    # 实例化测试加载器
    loader = unittest.TestLoader()
    # 模块名
    testsuite.addTest(loader.loadTestsFromName('TestCase1'))
    # 测试类名
    testsuite.addTest(loader.loadTestsFromName('TestCase1.TestCase1'))
    # 测试类中的测试方法名
    testsuite.addTest(loader.loadTestsFromName('TestCase1.TestCase1.test1'))

    return testsuite


# loadTestsFromNames(names) 与name功能相同,区别是接收的参数是字符串列表
def suite8():
    # 实例化测试套件
    testsuite = unittest.TestSuite()
    # 实例化测试加载器
    loader = unittest.TestLoader()
    # 模块名、测试类名、测试类中的测试方法名
    testsuite.addTest(loader.loadTestsFromNames(['TestCase1', 'TestCase.TestCase1', 'TestCase.TestCase1.test1']))

    return testsuite


# discover(start_dir, pattern) 根据指定的目录和匹配规则,递归所有子目录模糊查询加载测试用例
def suite9():
    # 实例化测试套件
    testsuite = unittest.TestSuite()
    # 实例化测试加载器
    loader = unittest.TestLoader()
    # 根据指定的目录和匹配规则,递归所有子目录模糊查询加载测试用例
    testsuite.addTest(loader.discover(start_dir='./', pattern='test*.py'))

    return testsuite

4. Run the test case

Run test cases and generate test reports. This step can be split into the following steps:

  1. Instantiate a test suite
  2. Load test cases into the test suite
  3. run test suite
  4. Generate test report
import unittest
import TestCase1


# discover(start_dir, pattern) 根据指定的目录和匹配规则,递归所有子目录模糊查询加载测试用例
def suite():
    # 实例化测试套件
    testsuite = unittest.TestSuite()
    # 实例化测试加载器
    loader = unittest.TestLoader()
    # 根据指定的目录和匹配规则,递归所有子目录模糊查询加载测试用例
    testsuite.addTest(loader.discover(start_dir='./', pattern='test*.py'))

    return testsuite


# 运行测试套件
if __name__ == '__main__':
    suite = suite()
    # 测试运行器,存储测试结果,并以文本的形式输出
    runner = unittest.TextTestRunner(verbosity=2)  # 控制台打印日志详细程度参数:verbosity=0(静默模式)、verbosity=1(默认模式)、verbosity=2(详细模式)
    runner.run(suite)

Console print log verbosity parameter: verbosity

  • verbosity=0 (silent mode): Only the total number of test cases and total results can be obtained. For example: a total of 100, success 80, failure 20.
  • verbosity=1 (default mode): Very similar to silent mode, except that there is a "." in front of each successful test case and an "E" in front of each failed test case.
  • verbosity=2 (verbosity mode): The test results will display all relevant information of each test case.

5. Generate a test report in HTML format

The test runner TextTestRunner outputs the test results in text format, which is inconvenient to display the test results. The third-party plug-ins downloaded from the PyPI official website: HTMLTestRunner and BeautifulReport can save the test results as html files.

import unittest
from HtmlTestRunner import HTMLTestRunner
from BeautifulReport import BeautifulReport


def suite():
    # 实例化测试套件
    testsuite = unittest.TestSuite()
    # 实例化测试加载器
    loader = unittest.TestLoader()
    # 根据指定的目录和匹配规则,递归所有子目录模糊查询加载测试用例
    testsuite.addTest(loader.discover(start_dir='./', pattern='TestCase2.py'))

    return testsuite


# # TextTestRunner
# if __name__ == '__main__':
#     suite = suite()
#     with open(file='../reports/MyReport.txt', mode='w') as file:
#         # 测试运行器,存储测试结果,并以文本的形式输出
#         runner = unittest.TextTestRunner(verbosity=2)  # 控制台打印日志详细程度参数:verbosity=0(静默模式)、verbosity=1(默认模式)、verbosity=2(详细模式)
#         runner.run(suite)

# # HTMLTestRunner
# if __name__ == '__main__':
#     suite = suite()
#     # combine_reports:将测试报告合并为单个测试报告(默认情况下,将为每个TestCase生成单独的测试报告)。
#     # output:测试报告保存路径。
#     # report_name:测试报告名称。
#     # add_timestamp:测试报告名称加上时间戳。
#     runner = HTMLTestRunner(combine_reports=True,
#                             output='../reports',
#                             report_name='MyReport',
#                             add_timestamp=False)
#     runner.run(suite)

# BeautifulReport
if __name__ == '__main__':
    suite = suite()
    result = BeautifulReport(suite)

    # filename -> 测试报告名称, 如果不指定默认文件名为report.html
    # description -> 测试报告用例名称展示
    # report_dir = '.' -> 报告文件写入路径
    # theme = 'theme_default' -> 报告主题样式:theme_default、theme_cyan、theme_candy、theme_memories

    # add_test_img(*pargs)
    # 可以在测试用例上挂载一个装饰器, 实例内容如下:
    # 默认存放的图片路径是img, 需要在当前测试项目的启动路径下, 创建一个img文件夹;
    # 传递给装饰器的图片, 在运行测试前可以不存在, 运行测试之后生成即可;
    # 当文件在报告中展示后, 想要看到原图, 可以点击报告中的缩略图查看完整的截图.

    result.report(filename='测试报告',
                  description='test',
                  report_dir='../reports',
                  theme='theme_memories')

Use the chrome browser to open the test report as follows:
insert image description here
insert image description here
insert image description here

6. Run in command line mode

unittest can also run test cases via command line mode. Several common commands are as follows:

  • python -m unittest: exploratory testing, by default, all test files in the test*.py mode are searched in the current directory and its subdirectories.
  • python -m unittest test_module1
  • python -m unittest test_module1 test_module2
  • python -m unittest test_module.TestClass
  • python -m unittest test_module.TestClass.test_method
  • python -m unittest tests/test_something.py

Open the Terminal terminal, enter the path testcases, and enter the command: python -m unittest
insert image description here

7. Skip test (test function/test class)

  • @unittest.skip(reason), skip tests decorated by this decorator. reason is the reason for skipping the test.
  • @unittest.skipIf(condition, reason), when the condition is true, skip the decorated test.
  • @unittest.skipUnless(condition, reason), skip the decorated test, unless the condition is true.
  • TestCase.skipTest(), directly skip the test and throw a SkipTest exception.
  • @unittest.expectedFailure, marks a test case as expected failure.

8. Precautions

  • Execution order of test cases: load according to the order of ASCII codes, the order of numbers and letters is: 0-9, AZ, az.
  • If the setUp() method throws an exception, the testing framework will consider the test to have an error, so the test method will not be run.
  • If setUp() runs successfully, tearDown() runs regardless of the success of the test method.
  • The setUp() and tearDown() of skipped tests will not be run.
  • setUpClass() and tearDownClass() of skipped classes will not be run.
  • The setUpModule() and tearDownModule() of skipped modules will not be run.

2. API

1. TestCase test case

  • setUp: pre-processing, function level, this method will be called before calling each test function. Except for AssertionError or SkipTest, any exception raised by this method will be considered an error rather than a test failure. Do nothing by default.
  • tearDown: post-processing, function level, this method will be called after calling each test function. This method will be executed as long as setUp executes successfully regardless of whether the test is successful or not. Except for AssertionError or SkipTest, any exception raised by this method will be considered an error rather than a test failure. Do nothing by default.
  • setUpClass: preprocessing, test class level, class method that is called before tests in a single class are run. Use the @classmethod decorator.
  • tearDownClass: Post-processing, test class level, class method that is invoked after tests in a single class have run. Use the @classmethod decorator.
  • run: Run the test and save the test result to the TestResult object.
  • skipTest: Calling this method during the execution of a test method or setUp() will skip the current test.
  • fail: Fails immediately with the given message.
  • id: Returns the full name of the test method, including the module name and class name.
  • subTest: context manager.
  • 断言:assertEqual,assertNotEqual,assertTrue,assertFalse,…
  • Exceptions: assertRaises, assertWarns, assertLogs, …

2. TestSuite test suite

  • addTest(test): Add a TestCase or TestSuite to the test suite, test must be an instantiated object.
  • addTests(tests): Add multiple TestCase or TestSuite to the test suite, tests must be instantiated and iterable objects.
  • run(result): Run the test and save the test result to the TestResult object.

3. TestLoader test loader

  • loadTestsFromTestCase(testCaseClass): Load all test cases in a test class.
  • loadTestsFromModule(module): loads all test cases in a module.
  • loadTestsFromName(name): Load test cases according to the specified string, the string can be the module name, test class name, test method name in the test class.
  • loadTestsFromNames(names): Same function as name, the difference is that the received parameter is a list of strings.
  • discover(start_dir, pattern='test*.py'): According to the specified directory and matching rules, recursively query all subdirectories to load test cases.

4. TestResult test result

It is used to store the test results of TestCase.run() and TestSuite.run() in result, and the test report can be customized by extending this base class. Such as: HTML Test Runner.

5. TextTestRunner test runner

run(test): store test results and output them in text form, test can be TestCase or TestSuite.


reference: official document

Guess you like

Origin blog.csdn.net/weixin_56175092/article/details/131896863