1.认识单元测试
class Calculator: def __init__(self, a, b): self.a = a self.b = 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
import unittest from calculator import Calculator # 创建一个测试类必须要继承unittest模块的TestCase类 class MyTestCase(unittest.TestCase): # 创建一个测试方法必须以test开头 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, 10) def test_div(self): c = Calculator(10, 5) result = c.div() self.assertEqual(result, 2) if __name__ == '__main__': unittest.main()
2.重要概念
2.1 Test Case
是最小的测试单元,用于检查特定输入集合的特定返回值。unittest提供了TestCase基类。
2.2 Test Suite
测试套件是测试用例、测试套件或两者的集合,用于组装一组要运行的测试。unittest提供了TestSuite类来创建测试套件。
2.3 Test Runner
是一个组件,用于协调测试的执行并向用户提供结果。unittest提供了TextTestRunner类运行测试用例。
2.4 Test Fixture
代表执行一个或多个测试所需的环境设备,以及关联的清理动作。
import unittest from calculator import Calculator # 创建一个测试类必须要继承unittest模块的TestCase类 class TestCalculator(unittest.TestCase): # 测试用例的前置动作 def setUp(self): print("test start:") # 测试用例的后置动作 def tearDown(self): print("test end") # 创建一个测试方法必须以test开头 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, 10) def test_div(self): c = Calculator(10, 5) result = c.div() self.assertEqual(result, 2) 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() runner.run(suit)
3.断言方法
import unittest class TestAssert(unittest.TestCase): def test_equal(self): self.assertEqual(2+2, 4) self.assertEqual("python", "python") self.assertNotEqual("hello", "love") def test_in(self): self.assertIn("hello", "hello world") self.assertNotIn("hi", "hello") def test_true(self): self.assertTrue(True) self.assertFalse(False) if __name__ == '__main__': unittest.main()
4.测试用例的组织与discover方法
class LeapYear: def __init__(self, year): self.year = year def answer(self): year = self.year if year % 100 == 0: if year % 400 == 0: return "{0}是闰年".format(year) else: return "{0}不是闰年".format(year) else: if year % 4 == 0: return "{0}是闰年".format(year) else: return "{0}不是闰年".format(year)
import unittest from leapyear import LeapYear class TestLeapYear(unittest.TestCase): def test_2000(self): ly = LeapYear(2000) self.assertEqual(ly.answer(), "2000是闰年") def test_2001(self): ly = LeapYear(2001) self.assertEqual(ly.answer(), "2001是闰年") if __name__ == "__main__": unittest.main()
import unittest # 定义测试用例的目录为当前目录中的test_case目录 test_dir = './test_case' suits = unittest.defaultTestLoader.discover(test_dir, pattern='test*.py') if __name__ == "__main__": runner = unittest.TextTestRunner() runner.run(suits)
1. 测试用例的执行顺序
unittest默认根据ASCII码的顺序加载测试用例(0~9,A~Z,a~z),可以通过使用套件来控制。
2.执行多级目录的测试用例
discover()方法只能加载写在方法里的目录的用例,可以通过给每个子目录下放一个__init__.py文件将一个子目录标记成一个标准的Python模块。
3.跳过测试和预期失败
import unittest class MyTest(unittest.TestCase): @unittest.skip("直接跳过测试") def test_skip(self): print("aaa") @unittest.skipIf(3 > 2, "当条件为真时跳过测试") def test_skip_if(self): print("bbb") @unittest.skipUnless(3 > 2, "当条件为真时执行测试") def test_skip_unless(self): print("ccc") # 不管执行结果如何都会标记失败,但不会抛出失败信息 @unittest.expectedFailure def test_expect_failure(self): self.assertEqual(2, 3) if __name__ == "__main__": unittest.main()
4.Fixture
即setUp/tearDown,还有测试类和模块的Fixture
import unittest def setUpModule(): print("test Module start >>>>>") def tearDownModule(): print("test module end >>>>>") class MyTest(unittest.TestCase): @classmethod def setUpClass(cls): print("test class start >>>>>") @classmethod def tearDownClass(cls): print("test class end >>>>>") def setUp(self): print("test case start >>>>>") def tearDown(self): print("test case end >>>>>") def test_case1(self): print("case1") def test_case2(self): print("case2") if __name__ == "__main__": unittest.main()
import unittest from time import sleep from selenium import webdriver class TestBaidu(unittest.TestCase): # 可以避免多次打开浏览器 @classmethod def setUpClass(cls): cls.driver = webdriver.Chrome() cls.base_url = "https://www.baidu.com" # 不是用例不会执行 def baidu_search(self, search_key): self.driver.get(self.base_url) self.driver.find_element_by_id("kw").send_keys(search_key) self.driver.find_element_by_id("su").click() sleep(2) def test_search_key_selenium(self): search_key = "selenium" self.baidu_search(search_key) self.assertEqual(self.driver.title, search_key+"_百度搜索") def test_search_unittest(self): search_key = "unittest" self.baidu_search(search_key) self.assertEqual(self.driver.title, search_key+"_百度搜索") @classmethod def tearDownClass(cls): cls.driver.quit() if __name__ == "__main__": unittest.main()