测试驱动开发
编写单元测试是一项收益极高的工作,它不光能让你更容易发现代码里的问题,还能驱动你写出更具扩展性的好代码。
Nameko 微服务框架对单元测试和集成测试有很好的支持:
- 提供了生成 nameko 服务实例和容器的工具方法
- 采用了依赖注入的理念,让依赖项更容易 Mock 和替换
- 集成了 pytest 库,直接使用 pytest 的语法来编写测试
话不多说,接下来我们开始编写单元测试。
单元测试优先
当按照上一章节《快速开始》的内容生成了一个 example 目录后,我们可以紧接着继续使用 namekoplus
命令在 example 目录下生成单元测试样例文件。
namekoplus test-gen -e example -t unit
-e
参数填写微服务代码文件所在的目录(必须填写一个已存在的 Nameko 服务目录);
-t
参数指定生成单元测试样例文件的类型,这里我们使用了unit
,代表单元测试。
在项目根目录运行上面的命令后,我们能看到文件 test_service.py
被生成了:
project_root_dir
├── example
│ ├── …………
│ ├── __init__.py
│ ├── test_service.py
打开 test_service.py
文件,我们能看到里面已经有了一个测试样例:
import pytest
from nameko.testing.services import worker_factory
@pytest.mark.parametrize(
'value, expected',
[
('John Doe', 'Hello, John Doe!'),
('', 'Hello, !'),
('Bryant', 'Hello, Bryant!'),
],
)
def test_example_service(value, expected):
"""
Test example service.
"""
# create worker with mock dependencies
service = worker_factory(ServiceName) # TODO replace ServiceName with the name of the service and import it
# add side effects to the mock rpc dependency on the "remote" service
service.remote.hello.side_effect = lambda name: "Hello, {}!".format(name)
# test remote_hello business logic
assert service.remote_hello(value) == expected
service.remote.hello.assert_called_once_with(value)
我们需要按照 #TODO 后面的提示,将 ServiceName
替换成我们将要测试的服务类名,并且在文件开头引入该服务类。
接着上一章《快速开始》的 example 示例,test_service.py
应该这样修改:
…………
from example.rpc_demo import RpcCallerDemoService
…………
def test_example_service(value, expected):
…………
service = worker_factory(RpcCallerDemoService)
…………
修改好 test_service.py
文件后,我们只需要在项目根目录运行 nameko test
命令,就能看到测试结果了:
========================================================================================================== test session starts ===========================================================================================================
platform darwin -- Python 3.11.4, pytest-7.4.0, pluggy-1.2.0
rootdir: /XXX/XXX/XXX/XXX
plugins: nameko-3.0.0rc11, anyio-3.7.1
collected 3 items
example/test_service.py ... [100%]
=========================================================================================================== 3 passed in 0.07s ============================================================================================================
至此,基于 example
目录下的 rpc_demo
服务,我们已经完成了一个单元测试样例的生成和运行。
往后,我们可以根据真正的项目需求,先在 test_service.py
文件里编写测试样例,运行一次测试,得到不通过的结果,然后再去实现对应服务的业务逻辑,再次运行测试,直到测试通过。
像这样把测试融入我们的开发流程中,保持“测试->开发->测试->开发->测试”这样的循环,那么我们的微服务代码质量就能得到保证。