使用代码库测试调用¶
测试使用invoke的代码库的策略;一些适用于专注于cli任务的代码,另一些适用于更通用/重构的设置。
子类和修改调用“internals”¶
一个简短的前言:大多数用户会发现后面的方法是合适的,但是高级用户应该注意到invoke的设计使其本身易于测试。这意味着,在许多情况下,即使调用的“内部”也被暴露为低/不共享的责任,公开文档类,可以被分类和修改,以注入测试友好的值或模拟。一定要检查一下 API documentation 你说什么?
使用 MockContext
¶
为测试目的对invoke的公共api进行子类化的实例是我们自己的 MockContext
. 代码基,它围绕 Context
对象及其方法(大多数面向任务的代码)将发现通过注入 MockContext
已实例化以产生部分 Result
物体。
例如,执行以下任务:
from invoke import task
@task
def show_platform(c):
uname = c.run("uname -s").stdout.strip()
if uname == 'Darwin':
print("You paid the Apple tax!")
elif uname == 'Linux':
print("Year of Linux on the desktop!")
测试它的一个例子 MockContext
可能如下(注: trap
is only one example of a common test framework tactic which mocks sys.stdout
/err
):
import sys
from spec import trap
from invoke import MockContext, Result
from mytasks import show_platform
@trap
def test_show_platform_on_mac():
c = MockContext(run=Result("Darwin\n"))
show_platform(c)
assert "Apple" in sys.stdout.getvalue()
@trap
def test_show_platform_on_linux():
c = MockContext(run=Result("Linux\n"))
show_platform(c)
assert "desktop" in sys.stdout.getvalue()
期待 Results
¶
核心调用子流程方法,如 run
全部返回 Result
对象(如上所述)可以仅用部分数据(例如标准输出,但不存在退出代码或标准错误)容易地实例化。
这意味着组织良好的代码可以更容易测试,并且不需要太多的使用。 MockContext
或终端输出模拟。
上一个示例的迭代:
from invoke import task
@task
def show_platform(c):
print(platform_response(c.run("uname -s")))
def platform_response(result):
uname = result.stdout.strip()
if uname == 'Darwin':
return "You paid the Apple tax!"
elif uname == 'Linux':
return "Year of Linux on the desktop!"
现在,大部分实际逻辑都是可测试的,代码行更少,对代码运行的“真实世界”的假设也更少(例如,不需要关心 sys.stdout
完全):
from invoke import Result
from mytasks import platform_response
def test_platform_response_on_mac():
assert "Apple" in platform_response(Result("Darwin\n"))
def test_platform_response_on_linux():
assert "desktop" in platform_response(Result("Linux\n"))
避免完全模拟依赖代码路径¶
这更像是一种通用的软件工程策略,但上述代码示例的自然终点是您的主逻辑根本不关心调用——只关心基本的python(或本地定义的)数据类型。这允许您单独测试逻辑,或者忽略对调用端的测试,或者只为代码与invoke接口的地方编写目标测试。
任务代码的另一个小调整:
from invoke import task
@task
def show_platform(c):
uname = c.run("uname -s").stdout.strip()
print(platform_response(uname))
def platform_response(uname):
if uname == 'Darwin':
return "You paid the Apple tax!"
elif uname == 'Linux':
return "Year of Linux on the desktop!"
还有测试:
from mytasks import platform_response
def test_platform_response_on_mac():
assert "Apple" in platform_response("Darwin\n")
def test_platform_response_on_linux():
assert "desktop" in platform_response("Linux\n")