跳转至

测试驱动开发

编写单元测试是一项收益极高的工作,它不光能让你更容易发现代码里的问题,还能驱动你写出更具扩展性的好代码。

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 文件里编写测试样例,运行一次测试,得到不通过的结果,然后再去实现对应服务的业务逻辑,再次运行测试,直到测试通过。

像这样把测试融入我们的开发流程中,保持“测试->开发->测试->开发->测试”这样的循环,那么我们的微服务代码质量就能得到保证。