跳转到主要内容

Python的模拟框架

项目描述

Func是一个受JMock影响的Python模拟框架。Func通过允许使用模拟对象代替“真实”对象,帮助测试模块的隔离。Func采用2条款BSD许可证。

安装

$ pip install funk

示例

假设我们有一个文件存储服务的API。我们想列出所有文件的名字,但是API限制了它一次返回的名字数量。因此,我们需要编写一些代码,不断向API请求数据,直到所有名字都被检索到。

def fetch_names(file_storage):
    has_more = True
    token = None
    names = []

    while has_more:
        response = file_storage.names(token=token)
        names += response.names
        token = response.next_token
        has_more = token is not None

    return names


import funk

@funk.with_mocks
def test_request_for_names_until_all_names_are_fetched(mocks):
    file_storage = mocks.mock(FileStorage)

    mocks.allows(file_storage).names(token=None).returns(mocks.data(
        next_token="<token 1>",
        names=["a", "b"],
    ))
    mocks.allows(file_storage).names(token="<token 1>").returns(mocks.data(
        next_token="<token 2>",
        names=["c", "d"],
    ))
    mocks.allows(file_storage).names(token="<token 2>").returns(mocks.data(
        next_token=None,
        names=["e"],
    ))

    assert fetch_names(file_storage) == ["a", "b", "c", "d", "e"]

通过使用模拟对象而不是FileStorage的真实实例,我们可以在没有运行文件存储系统实例的情况下运行我们的测试。我们还避免了依赖FileStorage的实现,使我们的测试更加集中,更少脆弱。

如果您使用pytest,使用Func的最简单方法是将它作为一个fixture使用

import funk
import pytest

@pytest.yield_fixture
def mocks():
    mocks = funk.Mocks()
    yield mocks
    mocks.verify()

def test_request_for_names_until_all_names_are_fetched(mocks):
    file_storage = mocks.mock(FileStorage)
    ...

用法

创建模拟上下文

创建一个Mocks实例以允许创建模拟对象。调用Mocks.verify()来断言所有预期都已满足。

import funk

def test_case():
    mocks = funk.Mocks()
    ...
    mocks.verify()

使用装饰器funk.with_mocks将一个mocks参数注入到一个函数中。函数结束时将自动调用verify()

import funk

@funk.with_mocks
def test_case(mocks):
    ...

如果您使用pytest,使用fixture是使用Func的最简单方法

import funk
import pytest

@pytest.yield_fixture
def mocks():
    mocks = funk.Mocks()
    yield mocks
    mocks.verify()

def test_case(mocks):
    ...

创建模拟对象

调用Mocks.mock()来创建模拟对象。

file_storage = mocks.mock()

如果传递了base参数,则只能模拟该类型的方法

file_storage = mocks.mock(FileStorage)

这可以确保仅模拟现有方法,但如果使用 __getattr__ 等动态生成方法时应该避免。

name 参数设置为在模拟断言失败消息中应使用的名称。

file_storage = mocks.mock(name="file_storage")

设置期望

要设置期望,请使用 funk.allows()funk.expects()。为了方便,这些函数也可以在 Mocks 上使用。funk.allows() 允许方法被调用任意次数,包括零次。funk.expects() 将确保方法被恰好调用一次。例如

allows(file_storage).names

这允许方法 file_storage.names 可以用任何参数调用任意次数。如果只想允许调用具有特定参数的方法,可以像调用方法一样调用 .names

allows(file_storage).names(token="<token 1>")

这将只允许带有匹配的 token 关键字参数的调用,不允许其他参数。

您还可以使用来自 Precisely 的匹配器来匹配参数。

from precisely import instance_of

allows(file_storage).names(token=instance_of(str))

如果在同一方法上设置了多个期望,则使用第一个匹配的期望。如果您需要强制按特定顺序调用方法,请使用序列。

操作

默认情况下,模拟方法返回 None。使用 returns() 返回不同的值。

allows(file_storage).names().returns([])

使用 raises() 抛出异常。

allows(file_storage).names().raises(Exception("Could not connect"))

序列

可以使用 Mocks.sequence 创建序列对象。然后可以在设置期望时使用 in_sequence(sequence) 定义对象的序列。例如

file_storage = mocks.mock(FileStorage)
file_ordering = mocks.sequence()

expects(file_storage).save(NAME_1, CONTENTS_1).in_sequence(file_ordering)
expects(file_storage).save(NAME_2, CONTENTS_2).in_sequence(file_ordering)

项目详情


下载文件

下载您平台的文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。

源分发

Funk-0.5.0.tar.gz (22.9 kB 查看散列)

上传时间

构建分发

Funk-0.5.0-py2.py3-none-any.whl (10.8 kB 查看散列)

上传时间 Python 2 Python 3

由以下赞助商支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面