标签:命令 down bec word error 一般来说 ken 错误信息 那是
2018年10月7日 星期日
11:39
unittest是python自带的单元测试框架,有时候又被称为”PyUnit”,是python版本的JUint实现。
该框架的作者是 Kent Beck和Erich Gamma,感谢祖师爷赏饭吃。
在学习使用unittest库之前,我们需要了解一下unittest库的一些重要概念:
总之
2018年10月7日 星期日
11:40
我们通过最简单的例子来看一下unittest的基本用法,下面的代码测试了3个python字符串方法,基本上满足了大部分情况下的测试需求
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual(‘foo‘.upper(), ‘FOO‘)
def test_isupper(self):
self.assertTrue(‘FOO‘.isupper())
self.assertFalse(‘Foo‘.isupper())
def test_split(self):
s = ‘hello world‘
self.assertEqual(s.split(),
[‘hello‘, ‘world‘])
# check that s.split fails when the separator is not a
string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == ‘__main__‘:
unittest.main()
解释一下关键点
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
除了使用unittest.main,还有其他的方式可以运行测试用例,比如把最后2行替换为
suite =
unittest.TestLoader().loadTestsFromTestCase(TestStringMethods)
unittest.TextTestRunner(verbosity=2).run(suite)
运行用例,结果将会如下所示
test_isupper
(__main__.TestStringMethods) ... ok
test_split (__main__.TestStringMethods) ... ok
test_upper (__main__.TestStringMethods) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK
2018年10月7日 星期日
11:41
背景
考虑这样一个测试弱密码的实例,这个我们在pytest相关教程中也有过描述。
我们需要判断用户的密码中包含简单密码,规则是这样的,密码必须至少6位,满足6位的话判断用户的密码不是password123或者password之类的弱密码。
对于如下的测试数据,我们要如何使用unittest来进行相关测试呢?
[
{"name":"jack","password":"Iloverose"},
{"name":"rose","password":"Ilovejack"},
{"name":"tom","password":"password123"}
]
Test fixture
前文我们也说过,text fixture的主要功能是初始化测试数据或环境以及清理测试数据或环境。
考虑上面的例子,对我们而已,在用例执行之前初始化上面的测试数据是有必要的,我们可以把上面的数据用python的数据结构来表示,比较合适的数据结构是python的字典。这样做有如下的好处
Test fixture最简单的实现方式是通过自定义下面的2个方法:
代码
新建名为test_password_1.py的文本文件,输入如下内容
import unittest
class PasswordTeseCase(unittest.TestCase):
def setUp(self):
print(‘set up‘)
self.test_data = [
dict(name=‘jack‘, password=‘Iloverose‘),
dict(name=‘rose‘, password=‘Ilovejack‘),
dict(name=‘tom‘, password=‘password123‘)
]
def test_week_password(self):
for data in
self.test_data:
passwd = data[‘password‘]
self.assertTrue(len(passwd) >= 6)
msg = "user %s has a weak password" %(data[‘name‘])
self.assertTrue(passwd != ‘password‘, msg)
self.assertTrue(passwd != ‘password123‘, msg)
def test_dummy(self):
pass
if __name__ == ‘__main__‘:
unittest.main()
运行
在命令行里输入 python test_password_1.py来运行用例,结果如下
$ python
test_password_1.py
set up
.set up
F
======================================================================
FAIL: test_week_password (__main__.PasswordTeseCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_password_1.py", line 21, in test_week_password
self.assertTrue(passwd != ‘password123‘, msg)
AssertionError: False is not true : user tom has a weak password
----------------------------------
Ran 2 tests in 0.001s
FAILED (failures=1)
解释一下
亲自动手试一试
假设我们增加1条测试数据,如下所示
[
{"name":"jack","password":"Iloverose"},
{"name":"rose","password":"Ilovejack"},
{"name":"tom","password":"password123"},
{"name":"jerry","password":"password"}
]
再运行上面的用例,观察一下测试结果是否会有不同?如果没有不同,那是为什么?
2018年10月7日 星期日
11:42
背景
接上一节的弱密码例子,我们的用例尽管运行的不错,但还是有点问题。
假如我们需要增加一些测试数据,那么我们就必须去修改setUp方法,在test_data列表中增加数据,频繁修改代码以适应一些不变的测试场景,这是没有必要的开销,可以想办法去优化。
我们可以把测试数据保存在文件里,通过读取文件的方式,每次动态从测试用例读取数据,这样数据的改变并不会影响用例,用例逻辑相对稳定,维护成本得到一定的降低。
设计测试数据
我们可以把测试数据保存成json格式,json格式的数据在各个语言间有较好的通用性,比较适合复用。
新建user_data.json文件,内容如下
[
{"name":"jack","password":"Iloverose"},
{"name":"rose","password":"Ilovejack"},
{"name":"tom","password":"password123"}
]
使用python的json库解析上面的json文件,可以得到如上节中test_data一致的数据。
代码
新建test_password_2.py,内容如下
import unittest
import json
class PasswordWithJsonTeseCase(unittest.TestCase):
data_file_path = ‘./user_data.json‘
def setUp(self):
print(‘set up‘)
self.test_data =
json.loads(open(self.data_file_path).read())
def test_week_password(self):
for data in
self.test_data:
passwd = data[‘password‘]
self.assertTrue(len(passwd) >= 6)
msg = "user %s has a weak password" %(data[‘name‘])
self.assertTrue(passwd != ‘password‘, msg)
self.assertTrue(passwd != ‘password123‘, msg)
def test_dummy(self):
pass
if __name__ == ‘__main__‘:
unittest.main()
跟上一节相比,最大的不同点是现在test_data通过解析json文件的方式来赋值self.test_data = json.loads(open(self.data_file_path).read())。
执行测试文件,结果应该与上一节一致。
发现问题
上面的代码有2个测试方法:test_week_password和test_dummy。由于setUp会在每个测试方法执行之前执行一次,那么setUp方法会执行2次,相应的json文件也会读取2次。如果测试方法多的话,那么反复读取json文件对性能来说是一个巨大的挑战。
优化
对于上面的测试数据读取场景,我们可以在所有测试方法执行前读取一次数据,毕竟测试数据在所有测试方法执行过程中是保持不变的。
setUpClass()和tearDownClass()
重构
下面我们重构代码以达到只读取1次测试数据的目的,新建文件`test_password_3.py,内容如下
import unittest
import json
class WeakPasswordTeseCase(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):
for data in
self.test_data:
passwd = data[‘password‘]
self.assertTrue(len(passwd) >= 6)
msg = "user %s has a weak password" %(data[‘name‘])
self.assertTrue(passwd != ‘password‘, msg)
self.assertTrue(passwd != ‘password123‘, msg)
def test_dummy(self):
pass
if __name__ == ‘__main__‘:
unittest.main()
有几点需要提及一下
2018年10月7日 星期日
11:43
背景
当我们的测试数据是下面这些的时候,我们的用例是有问题的。
[
{"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)
我们能学到什么
2018年10月7日 星期日
11:44
背景
unittest支持命令行接口,我们可以在命令行里指定运行具体的测试用例。
实例
在test_password_1.py中定义了PasswordTeseCase用例,我们可以从命令行中指定只运行该用例。
$
python -m unittest test_password_1.PasswordTeseCase
set up
.set up
F
======================================================================
FAIL: test_week_password (test_password_1.PasswordTeseCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/easonhan/code/testclass.net/src/pyunit/test_password_1.py", line 21, in
test_week_password
self.assertTrue(passwd != ‘password123‘, msg)
AssertionError: False is not true : user tom has a weak password
----------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (failures=1)
还可以使用-v参数来获得更详细的输出
$
python -m unittest test_password_1.PasswordTeseCase -v
test_dummy (test_password_1.PasswordTeseCase) ... set up
ok
test_week_password (test_password_1.PasswordTeseCase) ... set up
FAIL
======================================================================
FAIL: test_week_password (test_password_1.PasswordTeseCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/easonhan/code/testclass.net/src/pyunit/test_password_1.py", line 21, in
test_week_password
self.assertTrue(passwd != ‘password123‘, msg)
AssertionError: False is not true : user tom has a weak password
----------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (failures=1)
也可以在命令行中一次指定多个测试用例类,具体的大家可以自己尝试一下。
2018年10月7日 星期日
11:45
背景
unittest支持各种断言方法。
断言列表
方法 |
检查点 |
assertEqual(a, b) |
a == b |
assertNotEqual(a, b) |
a != b |
assertTrue(x) |
bool(x) is True |
assertFalse(x) |
bool(x) is False |
assertIs(a, b) |
a is b |
assertIsNot(a, b) |
a is not b |
assertIsNone(x) |
x is None |
assertIsNotNone(x) |
x is not None |
assertIn(a, b) |
a in b |
assertNotIn(a, b) |
a not in b |
assertIsInstance(a, b) |
isinstance(a, b) |
assertNotIsInstance(a, b) |
not isinstance(a, b) |
assertRaises(exc, fun, *args, **kwds) |
fun(*args, **kwds) raises exc |
assertRaisesRegexp(exc, r, fun, *args, **kwds) |
fun(*args, **kwds) raises exc and the message matches regex r |
assertAlmostEqual(a, b) |
round(a-b, 7) == 0 |
assertNotAlmostEqual(a, b) |
round(a-b, 7) != 0 |
assertGreater(a, b) |
a > b 2.7 |
assertGreaterEqual(a, b) |
a >= b |
assertLess(a, b) |
a < b |
assertLessEqual(a, b) |
a <= b |
assertRegexpMatches(s, r) |
r.search(s) |
assertNotRegexpMatches(s, r) |
not r.search(s) |
assertItemsEqual(a, b) |
sorted(a) == sorted(b) 也支持unhashable对象 |
assertDictContainsSubset(a, b) |
a里面所有的键值对都在b中存在 |
自己动手
大家可以自己动手亲自尝试使用这些断言方法。
2018年10月7日 星期日
11:45
背景
我们有时候需要断言一些方法会抛出异常,这些异常需要符合我们的预期。
代码
新建test_exception.py文件,内容如下
import unittest
class DivZeroTestCase(unittest.TestCase):
def test_should_raise_exception(self):
with self.assertRaises(ZeroDivisionError):
1 / 0
if __name__ == ‘__main__‘:
unittest.main()
运行及结果
$ python
test_exception.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
我们能学到什么
标签:命令 down bec word error 一般来说 ken 错误信息 那是
原文地址:https://www.cnblogs.com/hellangels333/p/9749897.html