【unittest单元测试框架】(1)认识 unittest
认识 unittest
1、认识单元测试
不用单元测试框架能写单元测试吗?答案是肯定的。单元测试本质上就是通过一段代码去验证另外一段代码,所以不用单元测试框架也可以写单元测试。下面就通过例子演示:
创建一个被测试文件 calculator.py:
# -*- coding:utf-8 -*- # filename: calculator # author: hello.yin class Calculator: def __init__(self, a, b): self.a = int(a) self.b = int(b) def add(self): return self.a + self.b def sub(self): return self.a - self.b def mul(self): return self.a * self.b def div(self): return self.a / self.b
程序非常简单,创建一个 Calculator 类,通过__init__()方法接收两个参数,并做 int 类型转换。创建 add()、sub()、mul()、div()方法分别进行加、减、乘、除运算。
根据上面实现的功能,创建 test_calculator.py 文件。
# -*- coding:utf-8 -*- # filename: calculator_test.py # author: hello.yin from calculator import Calculator def test_add(): c = Calculator(3, 5) result = c.add() assert result == 8 def test_sub(): c = Calculator(3, 5) result = c.sub() assert result == -2 def test_mul(): c = Calculator(3, 5) result = c.mul() assert result == 15 def test_div(): c = Calculator(3, 5) result = c.div() assert result == 3/5 if __name__ == "__main__": test_add() test_sub() test_mul() test_div()
在测试代码中,首先引入 calculator 文件中的 Calculator 类,并对测试数据进行初始化。接下来调用该类下面的方法,得到计算结果,并断言结果是否正确。
这样的测试存在着一些问题。首先,我们需要自己定义断言失败的提示;其次,当一个测试函数运行失败后,后面的测试函数将不再执行;最后,执行结果无法统计
当然,我们可以通过编写更多的代码来解决这些问题,但这就偏离了我们做单元测试的初衷。我们应该将重点放在测试本身,而不是其他上面。引入单元测试框架可以很好地解决这些问题。
下面通过 unittest 单元测试框架重新编写测试用例。
# -*- coding:utf-8 -*- # filename: calculator_test.py # author: hello.yin # create time:2021/11/16 11:07 import unittest from calculator import Calculator class TestCalculator(unittest.TestCase): def test_add(self): c = Calculator(3, 5) result = c.add() self.assertEqual(result, 8) def test_sub(self): c = Calculator(3, 5) result = c.sub() self.assertEqual(result, -2) def test_mul(self): c = Calculator(3, 5) result = c.mul() self.assertEqual(result, 15) def test_div(self): c = Calculator(3, 5) result = c.div() self.assertEqual(result, 3/5) if __name__ == "__main__": unittest.main(verbosity=2)
执行结果:
C:\Users\yzp\PycharmProjects\base_practice\Scripts\python.exe D:/00test/base_practice/calculator_test.py test_add (__main__.TestCalculator) ... ok test_div (__main__.TestCalculator) ... ok test_mul (__main__.TestCalculator) ... ok test_sub (__main__.TestCalculator) ... ok ---------------------------------------------------------------------- Ran 4 tests in 0.000s OK Process finished with exit code 0
2、重要的概念
1.Test Case
2.Test Suite
3.Test Runner
4.Test Fixture
# -*- coding:utf-8 -*- # filename: calculator_test.py # author: hello.yin # create time:2021/11/16 11:07 import unittest from calculator import Calculator class TestCalculator(unittest.TestCase): # 测试用例执行前置动作 def setUp(self): print("start test case!") # 测试用例执行后置动作 def tearDown(self): print("end test case!") def test_add(self): c = Calculator(3, 5) result = c.add() self.assertEqual(result, 8) def test_sub(self): c = Calculator(3, 5) result = c.sub() self.assertEqual(result, -2) def test_mul(self): c = Calculator(3, 5) result = c.mul() self.assertEqual(result, 15) def test_div(self): c = Calculator(3, 5) result = c.div() self.assertEqual(result, 3/5) if __name__ == "__main__": # 创建测试套件 suit = unittest.TestSuite() suit.addTest(TestCalculator("test_add")) suit.addTest(TestCalculator("test_sub")) suit.addTest(TestCalculator("test_mul")) suit.addTest(TestCalculator("test_div")) # 创建测试运行器 runner = unittest.TextTestRunner(verbosity=2) runner.run(suit)
其次,当一个测试文件中有很多测试用例时,并不是每次都要执行所有的测试用例,尤其是比较耗时的 UI 自动化测试。因而通过测试套件和测试运行器可以灵活地控制要执行的测试用例。
C:\Users\yzp\PycharmProjects\base_practice\Scripts\python.exe D:/00test/base_practice/calculator_test.py test_add (__main__.TestCalculator) ... ok test_sub (__main__.TestCalculator) ... ok test_mul (__main__.TestCalculator) ... ok test_div (__main__.TestCalculator) ... ok start test case! end test case! start test case! ---------------------------------------------------------------------- end test case! start test case! end test case! start test case! Ran 4 tests in 0.000s end test case! OK Process finished with exit code 0
从执行结果可以看到,setUp/tearDown 作用于每条测试用例的开始之处与结束之处。
3、断言方法
断言方法的使用如下所示:
# -*- coding:utf-8 -*- # filename: assert_test # author: hello.yin # create time: 2021/11/16 13:43 import unittest class AssertTest(unittest.TestCase): def setUp(self): print("case前置执行") def tearDown(self): print("case后置执行") def test_assertEqual(self): self.assertEqual(2, 2) self.assertNotEqual(2, 3) def test_assertTrue(self): self.assertTrue(1) self.assertFalse(0) def test_assertIn(self): self.assertIn("hello", "hello.yin") self.assertNotIn("hello", "hi.yin") def test_assertIs(self): self.assertIs("a", "a") self.assertIsNone(None) if __name__ == "__main__": suit = unittest.TestSuite() suit.addTest(AssertTest("test_assertEqual")) suit.addTest(AssertTest("test_assertTrue")) suit.addTest(AssertTest("test_assertIn")) suit.addTest(AssertTest("test_assertIs")) runner = unittest.TextTestRunner(verbosity=2) runner.run(suit)
执行结果:
Testing started at 13:54 ... C:\Users\yzp\PycharmProjects\base_practice\Scripts\python.exe "C:\Program Files\JetBrains\PyCharm 2018.2\helpers\pycharm\_jb_unittest_runner.py" --path D:/00test/base_practice/assert_test.py Launching unittests with arguments python -m unittest D:/00test/base_practice/assert_test.py in D:\00test\base_practice case前置执行 case后置执行 case前置执行 case后置执行 case前置执行 case后置执行 case前置执行 case后置执行 Ran 4 tests in 0.014s OK Process finished with exit code 0
4、测试用例的组织与 discover 方法
前面针对 Calculator 类所编写的测试用例存在以下问题。
# -*- coding:utf-8 -*- # filename: leap_year.py # author: hello.yin # create time: 2021/11/16 14:13 class LeapYear: def __init__(self, year): self.year = int(year) def answer(self): year = self.year if year % 100 == 0: if year % 400 == 0: return "{}是闰年".format(year) else: return "{}不是闰年".format(year) else: if year % 4 == 0: return "{}是闰年".format(year) else: return "{}不是闰年".format(year)
创建对应的测试文件 test_leap_year.py
# -*- coding:utf-8 -*- # filename: test_leap_year.py # author: hello.yin # create time: 2021/11/16 14:26 from leap_year import LeapYear import unittest class TestLeapYear(unittest.TestCase): def setUp(self): print("case开始测试!") def tearDown(self): print("case结束测试!") def test_2000(self): result = LeapYear(2000) self.assertEqual(result.answer(), "2000是闰年") def test_2100(self): result = LeapYear(2100) self.assertEqual(result.answer(), "2100不是闰年") def test_2004(self): result = LeapYear(2004) self.assertEqual(result.answer(), "2004是闰年") def test_2007(self): result = LeapYear(2007) self.assertEqual(result.answer(), "2007不是闰年") if __name__ == "__main__": suit = unittest.TestSuite() suit.addTest(TestLeapYear("test_2000")) suit.addTest(TestLeapYear("test_2100")) suit.addTest(TestLeapYear("test_2004")) suit.addTest(TestLeapYear("test_2007")) runner = unittest.TextTestRunner(verbosity=2) runner.run(suit)

discover(start_dir,pattern='test*.py',top_level_dir=None)
- start_dir :待测试的模块名或测试用例目录。
- pattern='test*.py' :测试用例文件名的匹配原则。此处匹配文件名以“test”开头的“.py”类型的文件,星号“*”表示任意多个字符。
- top_level_dir=None:测试模块的顶层目录,如果没有顶层目录,则默认为 None。
# -*- coding:utf-8 -*- # filename: run_test.py # author: hello.yin # create time: 2021/11/16 14:47 import unittest # 定义测试用例所在目录为当前所在目录的/test_case test_dir = "./test_case" suits = unittest.defaultTestLoader.discover(test_dir, pattern="*test*.py") if __name__ == "__main__": runner = unittest.TextTestRunner(verbosity=2) runner.run(suits)
执行结果:
C:\Users\yzp\PycharmProjects\base_practice\Scripts\python.exe D:/00test/base_practice/run_test.py start test case! end test case! test_add (test_calculator.TestCalculator) ... ok start test case! end test case! start test case! test_div (test_calculator.TestCalculator) ... ok end test case! start test case! end test case! case开始测试! test_mul (test_calculator.TestCalculator) ... ok case结束测试! case开始测试! case结束测试! case开始测试! case结束测试! case开始测试! case结束测试! test_sub (test_calculator.TestCalculator) ... ok test_2000 (test_leap_year.TestLeapYear) ... ok test_2004 (test_leap_year.TestLeapYear) ... ok test_2007 (test_leap_year.TestLeapYear) ... ok test_2100 (test_leap_year.TestLeapYear) ... ok ---------------------------------------------------------------------- Ran 8 tests in 0.000s OK Process finished with exit code 0
本博客所有文章仅用于学习、研究和交流目的,欢迎非商业性质转载。
本文来自博客园,作者:hello_殷,转载请注明原文链接:https://www.cnblogs.com/yinzuopu/p/15560423.html
浙公网安备 33010602011771号