1.测试用例的组织与discover方法
一个功能对应一条测试用例显然是不够的,要写多少测试用例取决于你对功能需求与测试方法的理解。
其次,是测试用例的划分,建议一个测试类对应一个被测试功能。
例如这样
class TestAdd(unittest.TestCase):
"""add()方法测试"""
def test_add1(self):
"""整数相加测试"""
c= Calculator(1,2)
result = c.add()
self.assertEqual(result,3)
def test_add2(self):
"""小数相加测试"""
c= Calculator(1.1,2.3)
result = c.add()
self.assertEqual(result,3)
def test_add3(self):
"""字符串整数相加测试"""
c= Calculator("1","2")
result = c.add()
self.assertEqual(result,3)
我们可以在一个测试文件中定义多个测试类,只要它们遵循测试用例的“规则”,main0方法就可以找到并执行它们。但是,我们要测试的类或方法可能有很多。
下面假设开发了一个登录功能,创建login.py文件。创建对应的测试文件test_login.py。
当前目录结构如下
![image-20191015150101430](/Users/x1you/Library/Application Support/typora-user-images/image-20191015150101430.png)
如何执行多个测试文件呢?unittest中的TestLoader类提供的discover()方法可以从多个文件中查找测试用该类根据各种标准加载测试用例,并将它们返回给测试套件。正常情况下,不需要创建这个类的实例。
unittest提供了可以共享的defaultTestLoader类,可以使用其子类或方法创建实例,discover()方法就是其中之一。
unittest.defaultTestLoader.discover(start_dir,pattern='test*.py',top_level_dir=None)
找到指定目录及其子目录下的所有测试模块,只有匹配的文件名才能被加载。如果启动的不是顶层目录,那么顶层目录必须单独指定。
- start_dir:待测试的模块名或测试用例目录。
- pattern='test.py':测试用例文件名的匹配原则。此处匹配文件名以“test”开头的“.py”类型的文件,星号“”表示任意多个字符。
- top_level_dir=None:测试模块的顶层目录,如果没有顶层目录,则默认为None。
现在通过discover0方法重新实现run_tests.py文件的功能。
discover()方法会自动根据测试用例目录(test_dir)查找测试用例文件(test*.py),并将找到的测试用例添加到测试套件中,因此,可以直接通过run()方法执行测试套件suits。这种方式极大地简化了测试用例的查找,我们需要做的就是按照文件的匹配规则创建测试文件即可。
2.关于unittest还需要知道的
-
测试用例的执行顺序
测试用例的执行顺序涉及多个层级:多个测试目录>多个测试文件>多个测试方法(测试用例)。unittest提供的main()方法和discover()方法是按照什么顺序查找测试用例的呢?
其实,unittest默认根据ASCII码的顺序加载测试用例的(数字与字母的顺序为0~9,A~Z,a~z),所以TestAdd类会优先于TestBdd类被执行,testaaa()方法会优先于test_ccc()方法被执行,也就是说,它并不是按照测试用例的创建顺序从上到下执行的。
discover()方法和main()方法的执行顺序是一样的。对于测试目录与测试文件来说,上面的规律同样适用。test_aaa.py文件会优先于test_bbb.py文件被执行。所以,如果想让某个测试文件先执行,可以在命名上加以控制。
当然,也可以用到前面介绍过的测试套件TestSuite,通过addTest()方法将测试用例加入测试套件,则会按照套件里的添加顺序去加载测试用例。
不过,当测试用例非常多时,不推荐用这种方法创建测试套件,最好的方法是通过命名控制执行顺序。如果测试用例在设计时不产生相互依赖,那么测试用例的执行顺序就没那么重要了。
-
执行多级目录的测试用例
![image-20191018094430243](/Users/x1you/Library/Application Support/typora-user-images/image-20191018094430243.png)
对于上面的目录结构,如果将discove()方法中的start_dir参数定义为"/test_case”目录,那么只能加载test_logout.py文件中的测试用例。如何让unittest查找test case/下子目录中的测试文件呢?方法很简单,就是在每个子目录下放一个
__init__.py
文件。__init__.py
文件的作用是将一个目录标记成一个标准的Python模块。 -
跳过测试和预期失败
在运行测试时,有时需要直接跳过某些测试用例,或者当测试用例符合某个条件时跳过测试,又或者直接将测试用例设置为失败。unittest提供了实现这些需求的装饰器。
-
无条件地跳过装饰的测试,需要说明跳过测试的原因。
unittest.skip(reason)
-
如果条件为真,则跳过装饰的测试
unittest.skipIF(condition,reason)
-
当条件为真时,执行装饰的测试
unittest.expecteFailure()
-
不管执行结果是否失败,都将测试标记为失败。
unittest.expectedFailure
-
如下:
import unittest
class MyTest(unittest.TestCase):
@unittest.skip("直接跳过测试")
def test_skip(self):
print("test aaa")
@unittest.skipIf(3>2,"当条件为真时跳过测试")
def test_skip_if(self):
print('test bbb')
@unittest.skipUnless(3>2,"当条件为真时执行测试")
def test_skip_unless(self):
print('test ccc')
@unitest.expectedFailure
def test_expected_failure(self):
self.assertEqual(2,3)
if__name__ == '__main__':
unittest.main()