使用py.test fixture定义Docker集成测试环境的一组特定帮助程序。

pytest_docker_tools的Python项目详细描述


Pytest Docker工具

您已经编写了一个软件应用程序(使用任何语言),并已打包为Docker映像。现在,您希望在发布构建的映像之前对其进行冒烟测试,或者与其他容器进行一些集成测试。你:

  • 想用类似于docker compose.yml的方式来解释您的环境
  • 希望在测试运行时自动创建和销毁环境
  • 不想为创建测试环境编写大量样板代码
  • 希望能够并行运行测试
  • 希望测试可靠

py test docker tools是一组自以为是的助手,用于为烟雾测试和集成测试需求创建py.test设备。它努力使您的环境定义保持声明性,就像docker-compose.yml一样。它包含py.test fixture过载。它尽量不太神奇。

此库提供的主界面是一组"fixture factories"。它提供了一个fixture的"类内最佳"实现,然后允许您将其视为一个模板—以声明方式注入您自己的配置。您可以在conftest.py中定义您的fixture并从所有测试中访问它们,您还可以根据需要在各个测试模块中覆盖它们。

api是直接的,并且隐式地捕获规范中的相互依赖关系。例如,如果您构建了一个微服务并希望指向它的dns和一个模拟dns服务器,那么它可能是这样的:

# conftest.pyfromhttp.clientimportHTTPConnectionimportpytestfrompytest_docker_toolsimportbuild,containerfakedns_image=build(path='examples/resolver-service/dns',)fakedns=container(image='{fakedns_image.id}',environment={'DNS_EXAMPLE_COM__A':'127.0.0.1',})apiserver_image=build(path='examples/resolver-service/api',)apiserver=container(image='{apiserver_image.id}',ports={'8080/tcp':None,},dns=['{fakedns.ips.primary}'])@pytest.fixturedefapiclient(apiserver):port=apiserver.ports['8080/tcp'][0]returnHTTPConnection(f'localhost:{port}')

现在您可以创建一个测试来练习您的微服务:

# test_smoketest.pyimportsocketdeftest_my_frobulator(apiserver):sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))deftest_my_frobulator_works_after_restart(apiserver):apiserver.restart()sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))

在本例中,所有依赖项都将按顺序和每次会话解析一次:

  • 将获取最新的redis:latest
  • 容器映像将从db文件夹中的dockerfile生成。

每次测试一次:

  • 将创建一个新卷
  • 将从redis:latest创建新的"后端"容器。它将附加到新卷。
  • 将从新构建的容器创建新的"前端"容器。如果后端通过一个环境变量被赋予IP。容器中的端口3679将作为主机上的临时端口公开。

然后,测试可以运行并通过其短暂的高端口访问容器。测试结束时,环境将被丢弃。

如果测试失败,将捕获每个容器的docker日志输出并将其添加到测试输出中。

在这个例子中,您会注意到我们定义了一个apiclientfixture。当然,如果您使用它,它将隐式地拉入两个服务器设备和"工作":

# test_smoketest.pyimportjsondeftest_api_server(apiclient):apiclient.request('GET','/')response=apiclient.getresponse()assertresponse.status==200assertjson.loads(response.read())=={'result':'127.0.0.1'}

范围

所有的fixture工厂都使用scope关键字。使用这些工厂创建的夹具的行为将类似于具有该范围的任何py.test夹具。

在本例中,我们创建一个memcache,它的作用域是session和另一个module作用域。

# conftest.pyfrompytest_docker_toolsimportcontainer,fetchmemcache_image=fetch(repository='memcached:latest')memcache_session=container(image='{memcache_image.id}',scope='session',ports={'11211/tcp':None,},)memcache_module=container(image='{memcache_image.id}',scope='module',ports={'11211/tcp':None,},)

test_scope_1.py运行时,两个容器都没有运行,因此每个容器都会启动一个新实例。它们的作用域比单个的函数要长,因此它们在下一次需要它们的测试中保持活动状态。

# test_scope_1.pyimportsocketdeftest_session_1(memcache_session):sock=socket.socket()sock.connect(('127.0.0.1',memcache_session.ports['11211/tcp'][0]))sock.sendall(b'set mykey 0 600 4\r\ndata\r\n')sock.close()deftest_session_2(memcache_session):sock=socket.socket()sock.connect(('127.0.0.1',memcache_session.ports['11211/tcp'][0]))sock.sendall(b'get mykey\r\n')assertsock.recv(1024)==b'VALUE mykey 0 4\r\ndata\r\nEND\r\n'sock.close()deftest_module_1(memcache_module):sock=socket.socket()sock.connect(('127.0.0.1',memcache_module.ports['11211/tcp'][0]))sock.sendall(b'set mykey 0 600 4\r\ndata\r\n')sock.close()deftest_module_2(memcache_module):sock=socket.socket()sock.connect(('127.0.0.1',memcache_module.ports['11211/tcp'][0]))sock.sendall(b'get mykey\r\n')assertsock.recv(1024)==b'VALUE mykey 0 4\r\ndata\r\nEND\r\n'sock.close()

test_scope_2.py运行会话时,作用域容器仍在运行,因此它将被重用。但我们现在在一个新的模块中,因此模块作用域容器将被销毁。将创建一个新的空实例。

# test_scope_2.pyimportsocketdeftest_session_3(memcache_session):sock=socket.socket()sock.connect(('127.0.0.1',memcache_session.ports['11211/tcp'][0]))sock.sendall(b'get mykey\r\n')assertsock.recv(1024)==b'VALUE mykey 0 4\r\ndata\r\nEND\r\n'sock.close()deftest_module_3(memcache_module):sock=socket.socket()sock.connect(('127.0.0.1',memcache_module.ports['11211/tcp'][0]))sock.sendall(b'get mykey\r\n')assertsock.recv(1024)==b'END\r\n'sock.close()

平行度

集成测试和冒烟测试通常很慢,但是要花很多时间等待。所以并行运行测试是加快测试速度的一个很好的方法。pytest docker tools避免创建可能发生冲突的资源名称。也很容易不在乎你的服务势必如此。这意味着它非常适合与pytest xdist一起使用。

下面是一个最简单的例子,它只是测试在xdist下运行的redis fixture的100个实例的创建和销毁。创建一个test\u xlist.py插件:

importpytestfrompytest_docker_toolsimportcontainer,fetchmy_redis_image=fetch(repository='redis:latest')my_redis=container(image='{my_redis_image.id}',)@pytest.mark.parametrize("i",list(range(100)))deftest_xdist(i,my_redis):assertmy_redis.status=="running"

并使用:

pytest test_xdist.py -n auto

它将为每个核心创建一个worker并并行运行测试:

===================================== test session starts ======================================
platform darwin -- Python 3.6.5, pytest-3.6.3, py-1.5.4, pluggy-0.6.0
rootdir: ~/pytest-docker-tools, inifile:
plugins: xdist-1.22.2, forked-0.2, docker-tools-0.0.2
gw0 [100] / gw1 [100] / gw2 [100] / gw3 [100] / gw4 [100] / gw5 [100] / gw6 [100] / gw7 [100]
scheduling tests via LoadScheduling
......................................................................................... [ 82%]
...........                                                                              [100%]
================================= 100 passed in 70.08 seconds ==================================

工厂参考

容器

要在测试中创建容器,请使用容器fixture factory。

# conftest.pyfromhttp.clientimportHTTPConnectionimportpytestfrompytest_docker_toolsimportbuild,containerfakedns_image=build(path='examples/resolver-service/dns',)fakedns=container(image='{fakedns_image.id}',environment={'DNS_EXAMPLE_COM__A':'127.0.0.1',})apiserver_image=build(path='examples/resolver-service/api',)apiserver=container(image='{apiserver_image.id}',ports={'8080/tcp':None,},dns=['{fakedns.ips.primary}'])@pytest.fixturedefapiclient(apiserver):port=apiserver.ports['8080/tcp'][0]returnHTTPConnection(f'localhost:{port}')
0

此工厂的默认范围是函数。这意味着将为每个测试创建一个新容器。

fixture factory支持可以传递给docker pyrun方法的所有参数。请参见这里的了解所有信息。

任何字符串变量都是根据其他定义的fixture插值的。这意味着一个固定装置可以依赖于其他固定装置,它们将按顺序构建和运行。

例如:

# conftest.pyfromhttp.clientimportHTTPConnectionimportpytestfrompytest_docker_toolsimportbuild,containerfakedns_image=build(path='examples/resolver-service/dns',)fakedns=container(image='{fakedns_image.id}',environment={'DNS_EXAMPLE_COM__A':'127.0.0.1',})apiserver_image=build(path='examples/resolver-service/api',)apiserver=container(image='{apiserver_image.id}',ports={'8080/tcp':None,},dns=['{fakedns.ips.primary}'])@pytest.fixturedefapiclient(apiserver):port=apiserver.ports['8080/tcp'][0]returnHTTPConnection(f'localhost:{port}')
1

这将首先获取最新的redis:latest,然后从所提取的确切图像运行容器。请注意,如果不使用buildfetch来准备docker映像,则指定的标记或哈希必须已存在于运行测试的主机上。不存在对Docker图像的隐式获取。

测试完成后,容器将自动删除。

IP地址

如果容器仅连接到单个网络,则可以通过帮助器属性获取其IP地址。在这种环境下:

# conftest.pyfromhttp.clientimportHTTPConnectionimportpytestfrompytest_docker_toolsimportbuild,containerfakedns_image=build(path='examples/resolver-service/dns',)fakedns=container(image='{fakedns_image.id}',environment={'DNS_EXAMPLE_COM__A':'127.0.0.1',})apiserver_image=build(path='examples/resolver-service/api',)apiserver=container(image='{apiserver_image.id}',ports={'8080/tcp':None,},dns=['{fakedns.ips.primary}'])@pytest.fixturedefapiclient(apiserver):port=apiserver.ports['8080/tcp'][0]returnHTTPConnection(f'localhost:{port}')
2

您可以通过容器助手访问IP:

# conftest.pyfromhttp.clientimportHTTPConnectionimportpytestfrompytest_docker_toolsimportbuild,containerfakedns_image=build(path='examples/resolver-service/dns',)fakedns=container(image='{fakedns_image.id}',environment={'DNS_EXAMPLE_COM__A':'127.0.0.1',})apiserver_image=build(path='examples/resolver-service/api',)apiserver=container(image='{apiserver_image.id}',ports={'8080/tcp':None,},dns=['{fakedns.ips.primary}'])@pytest.fixturedefapiclient(apiserver):port=apiserver.ports['8080/tcp'][0]returnHTTPConnection(f'localhost:{port}')
3

如果您想通过网络查找它的IP地址,您还可以更具体地访问它:

# conftest.pyfromhttp.clientimportHTTPConnectionimportpytestfrompytest_docker_toolsimportbuild,containerfakedns_image=build(path='examples/resolver-service/dns',)fakedns=container(image='{fakedns_image.id}',environment={'DNS_EXAMPLE_COM__A':'127.0.0.1',})apiserver_image=build(path='examples/resolver-service/api',)apiserver=container(image='{apiserver_image.id}',ports={'8080/tcp':None,},dns=['{fakedns.ips.primary}'])@pytest.fixturedefapiclient(apiserver):port=apiserver.ports['8080/tcp'][0]returnHTTPConnection(f'localhost:{port}')
4

端口

工厂采用与官方python docker api相同的端口参数。我们建议使用短暂的高端口语法:

# conftest.pyfromhttp.clientimportHTTPConnectionimportpytestfrompytest_docker_toolsimportbuild,containerfakedns_image=build(path='examples/resolver-service/dns',)fakedns=container(image='{fakedns_image.id}',environment={'DNS_EXAMPLE_COM__A':'127.0.0.1',})apiserver_image=build(path='examples/resolver-service/api',)apiserver=container(image='{apiserver_image.id}',ports={'8080/tcp':None,},dns=['{fakedns.ips.primary}'])@pytest.fixturedefapiclient(apiserver):port=apiserver.ports['8080/tcp'][0]returnHTTPConnection(f'localhost:{port}')
5

Docker会将容器中的8080端口映射到主机上的一个随机端口。为了从测试中访问它,您可以从容器实例中获取绑定端口:

# conftest.pyfromhttp.clientimportHTTPConnectionimportpytestfrompytest_docker_toolsimportbuild,containerfakedns_image=build(path='examples/resolver-service/dns',)fakedns=container(image='{fakedns_image.id}',environment={'DNS_EXAMPLE_COM__A':'127.0.0.1',})apiserver_image=build(path='examples/resolver-service/api',)apiserver=container(image='{apiserver_image.id}',ports={'8080/tcp':None,},dns=['{fakedns.ips.primary}'])@pytest.fixturedefapiclient(apiserver):port=apiserver.ports['8080/tcp'][0]returnHTTPConnection(f'localhost:{port}')
6

日志

您可以使用logs方法检查容器的日志:

# conftest.pyfromhttp.clientimportHTTPConnectionimportpytestfrompytest_docker_toolsimportbuild,containerfakedns_image=build(path='examples/resolver-service/dns',)fakedns=container(image='{fakedns_image.id}',environment={'DNS_EXAMPLE_COM__A':'127.0.0.1',})apiserver_image=build(path='examples/resolver-service/api',)apiserver=container(image='{apiserver_image.id}',ports={'8080/tcp':None,},dns=['{fakedns.ips.primary}'])@pytest.fixturedefapiclient(apiserver):port=apiserver.ports['8080/tcp'][0]returnHTTPConnection(f'localhost:{port}')
7

图像

要从默认存储库中提取图像,请使用fetchfixture factory。要从本地源构建图像,请使用buildfixture factory。如果您正在对已在本地生成的工件进行烟雾测试,则可以使用图像fixture factory来引用它。

# conftest.pyfromhttp.clientimportHTTPConnectionimportpytestfrompytest_docker_toolsimportbuild,containerfakedns_image=build(path='examples/resolver-service/dns',)fakedns=container(image='{fakedns_image.id}',environment={'DNS_EXAMPLE_COM__A':'127.0.0.1',})apiserver_image=build(path='examples/resolver-service/api',)apiserver=container(image='{apiserver_image.id}',ports={'8080/tcp':None,},dns=['{fakedns.ips.primary}'])@pytest.fixturedefapiclient(apiserver):port=apiserver.ports['8080/tcp'][0]returnHTTPConnection(f'localhost:{port}')
8

fixture factory支持可以传递给docker pybuild方法的所有参数。请参见这里的了解所有内容。fixture factory支持可以传递给docker pypull方法的所有参数。请参见这里的了解所有信息。

此工厂的默认范围是会话。这意味着fixture每次py.test调用只构建或获取一次。在测试(或其他设备)尝试使用之前,设备不会被触发。这意味着如果不运行使用图像的测试,就不会浪费时间构建图像。

网络

默认情况下,使用container()fixture factory创建的任何容器都将在默认Docker网络上运行。您可以使用network()fixture factory为您的测试创建一个专用网络。

# conftest.pyfromhttp.clientimportHTTPConnectionimportpytestfrompytest_docker_toolsimportbuild,containerfakedns_image=build(path='examples/resolver-service/dns',)fakedns=container(image='{fakedns_image.id}',environment={'DNS_EXAMPLE_COM__A':'127.0.0.1',})apiserver_image=build(path='examples/resolver-service/api',)apiserver=container(image='{apiserver_image.id}',ports={'8080/tcp':None,},dns=['{fakedns.ips.primary}'])@pytest.fixturedefapiclient(apiserver):port=apiserver.ports['8080/tcp'][0]returnHTTPConnection(f'localhost:{port}')
9

fixture factory支持可以传递给docker py networkcreate方法的所有参数。S请参见此处为他们所有人创建" rel="nofollow"

此工厂的默认范围是函数。这意味着将为执行的每个测试创建一个新网络。

使用网络完成测试后,网络将被删除。

体积

理想情况下,Docker容器实例是只读的。如果容器中的数据是卷的,则不会写入容器中的数据。如果您正在测试您的服务是否可以以只读方式运行,则可能需要装载一个rw卷。您可以使用volume()fixture工厂创建一个docker卷,该卷的生命周期与您的测试绑定。

# test_smoketest.pyimportsocketdeftest_my_frobulator(apiserver):sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))deftest_my_frobulator_works_after_restart(apiserver):apiserver.restart()sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))
0

fixture factory支持可以传递给docker py volumecreate方法的所有参数。请参见这里的了解所有这些文件。

此外,您还可以指定一个初始目录字典。这允许您以一小组初始状态为卷设定种子。在下面的示例中,我们将展示一个minio服务,其中一个bucket中有两个bucket和一个object。

# test_smoketest.pyimportsocketdeftest_my_frobulator(apiserver):sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))deftest_my_frobulator_works_after_restart(apiserver):apiserver.restart()sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))
1

将使用一个空文件夹(bucket-1)和一个名为example.txt的文本文件在一个名为bucket-2的单独文件夹中创建minio-u卷容器

此工厂的默认范围是函数。这意味着将为执行的每个测试创建一个新卷。测试完成后,将删除卷。

固定装置

Docker_客户端

docker客户端的fixture返回官方docker客户端的一个实例。

# test_smoketest.pyimportsocketdeftest_my_frobulator(apiserver):sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))deftest_my_frobulator_works_after_restart(apiserver):apiserver.restart()sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))
2

直接使用Docker_客户端时要小心:

  • 显然,在测试结束时,不会自动删除通过api创建的必需资源
  • 很容易破坏xdist的兼容性
    • 始终使用ignore_removeddocker_client.containers.list()一起使用
    • 很容易找到正在使用的资源的其他实例(在其他worker中创建)。注意这个!
  • 不要采取破坏性措施-可能有人在机器上运行测试,而其他(非测试)容器正在运行,附带损坏很容易,应该避免。

这是我们夹具厂使用的夹具。这意味着如果你定义了一个自己的docker客户机fixture,那么测试将使用这个fixture。

提示和技巧

测试构建工件

我们经常发现自己对在测试时构建的容器(使用build())使用一组测试,但随后又希望对在ci平台上生成的工件(使用image())使用相同的测试。结果是这样的:

# test_smoketest.pyimportsocketdeftest_my_frobulator(apiserver):sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))deftest_my_frobulator_works_after_restart(apiserver):apiserver.restart()sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))
3

但现在你可以做到:

# test_smoketest.pyimportsocketdeftest_my_frobulator(apiserver):sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))deftest_my_frobulator_works_after_restart(apiserver):apiserver.restart()sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))
4

dev env和ci之间的网络差异

开发环境和ci环境之间的另一个常见区别可能是,测试最终在ci上的docker中运行。如果绑定mount yourdocker.sock,则测试可能最终在与测试容器相同的容器网络上运行,并且无法访问映射到主机盒的任何端口。换句话说:

  • 在您的开发机器上,您的测试可能会访问locahost:8000以访问您的测试实例(映射到主机的端口)
  • 在您的ci机器上,他们可能需要访问172.16.0.5:8000才能访问您的测试实例

container对象有一个get\u addr帮助程序,它将根据所在的环境返回正确的内容。

# test_smoketest.pyimportsocketdeftest_my_frobulator(apiserver):sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))deftest_my_frobulator_works_after_restart(apiserver):apiserver.restart()sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))
5

客户设备

您可能需要为正在测试的服务创建一个api客户端. 尽管我们已经在自述文件中做了这些,但值得一提。你可以定义一个客户端fixture,让它依赖于你的docker容器,然后只需要从你的测试中引用客户端。

# conftest.pyfromhttp.clientimportHTTPConnectionimportpytestfrompytest_docker_toolsimportbuild,containerfakedns_image=build(path='examples/resolver-service/dns',)fakedns=container(image='{fakedns_image.id}',environment={'DNS_EXAMPLE_COM__A':'127.0.0.1',})apiserver_image=build(path='examples/resolver-service/api',)apiserver=container(image='{apiserver_image.id}',ports={'8080/tcp':None,},dns=['{fakedns.ips.primary}'])@pytest.fixturedefapiclient(apiserver):port=apiserver.ports['8080/tcp'][0]returnHTTPConnection(f'localhost:{port}')

然后从测试中引用:

# test_smoketest.pyimportsocketdeftest_my_frobulator(apiserver):sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))deftest_my_frobulator_works_after_restart(apiserver):apiserver.restart()sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))
7

在本例中,任何使用hpfeeds_clientfixture的测试都将获得一个正确配置的客户端,该客户端连接到在临时高端口上的Docker容器中运行的代理。测试完成后,客户端将完全断开连接,Docker容器将被丢弃。

夹具过载

复杂的环境可以用夹具工厂来定义。它们形成有向无环图。通过使用fixture重载,可以(在单个测试模块的上下文中)替换依赖关系图中的节点,而无需重新定义整个环境。

无需重新定义其从属项即可更换容器夹具

您可以在conftest.py中定义一个fixture

# conftest.pyfromhttp.clientimportHTTPConnectionimportpytestfrompytest_docker_toolsimportbuild,containerfakedns_image=build(path='examples/resolver-service/dns',)fakedns=container(image='{fakedns_image.id}',environment={'DNS_EXAMPLE_COM__A':'127.0.0.1',})apiserver_image=build(path='examples/resolver-service/api',)apiserver=container(image='{apiserver_image.id}',ports={'8080/tcp':None,},dns=['{fakedns.ips.primary}'])@pytest.fixturedefapiclient(apiserver):port=apiserver.ports['8080/tcp'][0]returnHTTPConnection(f'localhost:{port}')

然后可以在测试模块中重载这些设备。例如,如果redis有一个神奇的复制特性,并且您想用api测试一个edge case,那么您可以在test戥smoketest戥alternate.py

# test_smoketest.pyimportsocketdeftest_my_frobulator(apiserver):sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))deftest_my_frobulator_works_after_restart(apiserver):apiserver.restart()sock=socket.socket()sock.connect(('127.0.0.1',apiserver.ports['8080/tcp'][0]))
9

在这里,我们在test\u smoketest\u alternate中重新定义了fakedns容器。它能够使用我们在conftest.py中定义的fakedns廑imagefixture。更重要的是,当我们使用coreapiclientfixture时,它实际上引入了fakedns的本地定义,而不是来自conftest.py的定义!你不必重新定义任何东西。它只是工作。

通过夹具注入夹具配置

你也可以从你的夹具工厂拉入普通的py.test夹具。这意味着我们可以使用fixture重载并传入config。在conftest.py中:

# test_smoketest.pyimportjsondeftest_api_server(apiclient):apiclient.request('GET','/')response=apiclient.getresponse()assertresponse.status==200assertjson.loads(response.read())=={'result':'127.0.0.1'}
0

当测试现在使用apiclient fixture时,他们将得到fakedns容器的配置为normal。但是,您可以在测试模块中重新定义fixture,其他fixture仍然会尊重它。例如:

# test_smoketest.pyimportjsondeftest_api_server(apiclient):apiclient.request('GET','/')response=apiclient.getresponse()assertresponse.status==200assertjson.loads(response.read())=={'result':'127.0.0.1'}
1

您的api_server容器(及其redis后端)将正常构建,只有在这一个测试模块中,它将使用其sqlite后端。

夹具参数化

可以创建参数化装置。也许您需要对两个身份验证后端运行所有的api_服务器测试。可能您有一个要测试的多个配置的赝品。

conftest.py中:

# test_smoketest.pyimportjsondeftest_api_server(apiclient):apiclient.request('GET','/')response=apiclient.getresponse()assertresponse.status==200assertjson.loads(response.read())=={'result':'127.0.0.1'}
2

测试与第一个示例相同,只是现在将针对两种不同的假配置进行测试。

# test_smoketest.pyimportjsondeftest_api_server(apiclient):apiclient.request('GET','/')response=apiclient.getresponse()assertresponse.status==200assertjson.loads(response.read())=={'result':'127.0.0.1'}
3

此测试将调用两次-一次针对内存后端,一次针对sqlite后端。

夹具包装

你可以用一个包装类来包装你的设备。这允许您向fixture添加helper方法,以便在测试中使用。对于容器夹具工厂,您还可以实现ready()以添加额外的容器就绪检查。

在以前的测试中,我们创建了一个完整的测试客户机fixture。使用wrapper类,我们可以把这个方便的方法挂在fixture本身上:

# test_smoketest.pyimportjsondeftest_api_server(apiclient):apiclient.request('GET','/')response=apiclient.getresponse()assertresponse.status==200assertjson.loads(response.read())=={'result':'127.0.0.1'}
4

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java允许具有不同父类的类扩展类,而无需多重继承   java如何创建动态化的JScrollPane w/JPanel作为客户端?   java如何组织和命名包   在Java中读取属性文件   java无法解释的Android意图行为   在Java中动态执行多个BPEL文件的部署   ssl Java 6 SNI(服务器名称指示)?   java我们可以使用Robot框架自动化web和移动应用程序来执行并行执行   java for star pettern的循环   java为什么BinaryReader在线程中,从netty读取错误的数据包?   在java中将华氏度转换为摄氏度   使用Spark和java处理空值和引号编写CSV文件   Java中已排序日期到块的列表   visual studio代码VSCode Java不是linting或自动完成局部变量,而是自动完成Java快捷方式,如“sysout”