背景

当我们的测试数据是下面这些的时候,我们的用例是有问题的。

[
  {"name":"jack","password":"Iloverose"},
  {"name":"rose","password":"Ilovejack"},
  {"name":"tom","password":"password123"},
  {"name":"jerry","password":"password"}
]

我们的用例只能找出tom是弱密码的用户,jerry这个用户会成为漏网之鱼。

为什么

这是因为在unittest中,一旦某个测试方法中的断言失败,后续的断言都不会被执行。

还原一下上面的例子,当用例在断言tom失败后,for循环就退出了,测试方法也执行完毕了,后面jerry这条数据就不会被断言。

怎么办

我们可以重构一下我们的用例,让整个用例只断言1次,断言失败以后就把弱密码的用户打印出来。

代码

修改user_data.json文件,加入一些测试数据,修改后的user_data.json文件应该是

[
  {"name":"jack","password":"Iloverose"},
  {"name":"rose","password":"Ilovejack"},
  {"name":"tom","password":"password123"},
  {"name":"jerry","password":"password"},
  {"name":"fred","password":"123456"},
  {"name":"elma","password":"654321"}
]

新建test_password_4.py文件,内容如下


import unittest
import json

class WeakPasswordTeseCase1(unittest.TestCase):

    @classmethod
    def setUpClass(kls):
        data_file_path = './user_data.json'
        print('before all test methods')
        with open(data_file_path) as f:
            kls.test_data = json.loads(f.read())

    def test_week_password(self):
        res = True
        msg = []
        for data in self.test_data:
            passwd = data['password']
            tmp_res = True

            tmp_res = tmp_res and (len(passwd) >= 6)
            tmp_res = tmp_res and (passwd != 'password')
            tmp_res = tmp_res and (passwd != 'password123')
            if not tmp_res:
                msg.append("user %s has a weak password %s" %(data['name'], data['password']))
            res = res and tmp_res

        self.assertTrue(res, "\n".join(msg))

    def test_dummy(self):
        pass

if __name__ == '__main__':
    unittest.main()

运行及结果

在命令行中运行python test_password_4.py,结果如下

$ python test_password_4.py
before all test methods
.F
======================================================================
FAIL: test_week_password (__main__.WeakPasswordTeseCase1)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_password_4.py", line 27, in test_week_password
    self.assertTrue(res, "\n".join(msg))
AssertionError: user tom has a weak password password123
user jerry has a weak password password

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)

我们能学到什么

  • 断言一旦失败之后测试方法就会结束运行,所以一般来说1个测试方法推荐只有1个断言
  • 如果一个测试方法里面必须要有多个断言,那么要确保前面的断言失败之后,后面的断言就算不运行也不会影响测试的范围和结果
  • for循环中的断言一旦失败,for循环就退出了
  • 上面演示的测试用例写法其实具备了一定的数据驱动测试的思想