软件开发更类似于手工艺,而不是工业。本章主要内容如下
- 软件测试和质量控制
- 自动测试和测试套件
- 测试驱动的开发
- 集成和功能测试
- 测试金字塔和奖杯
软件测试和质量控制
软件开发过程在很大程度上受到了制造业标准的启发,在早期,测试和质量控制被引入到产品开发周期中。软件公司经常有质量保证团队,专注于建立流程以保证软件的稳健性和跟踪结果。
质量控制过程通常通过测试计划的执行来实现这种信心。它通常是一个检查表,由专门的团队在生产的各个阶段进行检查,以确保软件的行为符合预期。需求和测试计划、测试用例、测试报告等关联,形成一个闭环。
自动测试
测试用例太多,很多时候需要对回归和手工不能实现的部分进行自动化。
自动化本身也是一种开发,需要对测试用例有一定的组织,为此产生了测试套件。
import unittest
class MyTestCase(unittest.TestCase):
def test_one(self):
pass
def notatest(self):
pass
class MySecondTestCase(unittest.TestCase):
def test_two(self):
pass
def test_two_part2(self):
pass
if __name__ == '__main__':
unittest.main()
执行示例:
$ python 01_automatictests.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
$ python 01_automatictests.py -v
test_two (__main__.MySecondTestCase) ... ok
test_two_part2 (__main__.MySecondTestCase) ... ok
test_one (__main__.MyTestCase) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
还可以分布在多个文件,比如
├──02_tests │
├── tests_div │
├─── __init__.py │ │
└── tests_div.py │ │
└── tests_sum.py
大多数测试是按照 "安排,行动,断言(Arrange, Act, Assert) "的模式来写的。
测试驱动的开发
测试可以做的不仅仅是验证我们的代码,测试在设计代码本身中是必不可少的。在实现代码之前编写测试,迫使我们对需求进行推理。
import unittest
class AdditionTestCase(unittest.TestCase):
def test_main(self):
result = addition(3, 2)
assert result == 5
def test_threeargs(self):
result = addition(3, 2, 1)
assert result == 6
def test_noargs(self):
result = addition()
assert result == 0
def addition(*args):
total = 0
for a in args:
total += a
return total
if __name__ == '__main__':
unittest.main()
集成和功能测试
集成测试是指不同架构组件的测试,比如:
import unittest
class Authentication:
USERS = [{"username": "user1",
"password": "pwd1"}]
def login(self, username, password):
u = self.fetch_user(username)
if not u or u["password"] != password:
return None
return u
def fetch_user(self, username):
for u in self.USERS:
if u["username"] == username:
return u
else:
return None
class Authorization:
PERMISSIONS = [{"user": "user1",
"permissions": {"create", "edit", "delete"}}]
def can(self, user, action):
for u in self.PERMISSIONS:
if u["user"] == user["username"]:
return action in u["permissions"]
else:
return False
class TestAuthentication(unittest.TestCase):
def test_login(self):
auth = Authentication()
auth.USERS = [{"username": "testuser", "password": "testpass"}]
resp = auth.login("testuser", "testpass")
assert resp == {"username": "testuser", "password": "testpass"}
def test_failed_login(self):
auth = Authentication()
resp = auth.login("usernotexisting", "")
assert resp is None
def test_wrong_password(self):
auth = Authentication()
auth.USERS = [{"username": "testuser", "password": "testpass"}]
resp = auth.login("testuser", "wrongpass")
assert resp == None
def test_fetch_user(self):
auth = Authentication()
auth.USERS = [{"username": "testuser", "password": "testpass"}]
user = auth.fetch_user("testuser")
assert user == {"username": "testuser", "password": "testpass"}
def test_fetch_user_not_existing(self):
auth = Authentication()
resp = auth.fetch_user("usernotexisting")
assert resp is None
class TestAuthorization(unittest.TestCase):
def test_can(self):
authz = Authorization()
authz.PERMISSIONS = [{"user": "testuser", "permissions": {"create"}}]
resp = authz.can({"username": "testuser"}, "create")
assert resp is True
def test_not_found(self):
authz = Authorization()
resp = authz.can({"username": "usernotexisting"}, "create")
assert resp is False
def test_unathorized(self):
authz = Authorization()
authz.PERMISSIONS = [{"user": "testuser", "permissions": {"create"}}]
resp = authz.can({"username": "testuser"}, "delete")
assert resp is False
class TestAuthorizeAuthenticatedUser(unittest.TestCase):
def test_auth(self):
auth = Authentication()
authz = Authorization()
auth.USERS = [{"username": "testuser", "password": "testpass"}]
authz.PERMISSIONS = [{"user": "testuser", "permissions": {"create"}}]
u = auth.login("testuser", "testpass")
resp = authz.can(u, "create")
assert resp is True
if __name__ == '__main__':
unittest.main()
功能测试倾向于验证我们是否向用户展示了我们真正想要的功能,多为黑盒测试。
端到端(E2E)测试是一种特殊的功能测试,涉及组件的垂直整合。
系统测试与功能测试本身非常相似,但不是测试单一功能,而是通常测试用户在系统中的整个流程。
验收测试是一种功能测试,多由用户进行。
单元和集成测试的目的是测试实现,而功能测试的目的是测试行为。
参考资料
测试分布模型
- 金字塔
- 奖杯
网友评论