如何在单元测试Django视图中避免组合爆炸

时间:2018-10-04 07:33:48

标签: python django unit-testing django-rest-framework

我有一个相当复杂的Django(Rest Framework)视图,该视图更新了数据库中的对象。

为了更新对象,需要满足一些条件(这些不是真实条件,但是它们是相似的):

  1. 用户必须登录
  2. 用户名必须以admin开头
  3. 根据某些规则,更新数据必须有效
  4. 一个单独的昂贵函数is_moon_phase_ok需要返回True

我正在尝试为此视图编写一套可靠的单元测试,而我提出的方案如下:

when not logged in, return 401
when not logged in, return {"fail": "login"}
when not logged in, don't touch database
when not logged in, don't check moon phase
when username is not admin_*, return 401
when username is not admin_*, return {"fail": "username"}
when username is not admin_*, don't touch database
when username is not admin_*, don't check moon phase
when invalid data, return 400
when invalid data, return {"fail": "data"}
when invalid data, don't touch database
when invalid data, don't check moon phase
when logged in, return 200
when logged in, return updated data
when logged in, check moon phase
when logged in, update database

您可以看到,每个单元测试都将花费大量代码来设置然后执行。就我而言,每个单元测试介于7到20行代码之间。

想象一下,如果需求发生了变化,并且确实发生了变化,那么忽略测试用例,确保它们仍然适用,根据新的需求进行更新等会带来多大的痛苦。

是否有更好的方法可以完成相同的工作,具有相同的测试覆盖率,却需要更少的人工呢?

1 个答案:

答案 0 :(得分:1)

对我来说,这听起来很像参数化测试,pytest支持此功能,基本上,您可以编写测试并提供输入参数,以及预期的效果。 因此,您只编写了一个测试,但足够通用以支持不同的参数,从而减少了维护代码。 pytest在后台使用定义的参数逐一运行相同的测试。 编写通用测试可能会引入一些逻辑(如您在我的示例中所看到的),但是我认为可以忍受这一点

作为一般示例:

@pytest.mark.parametrize('is_admin,expected_status_code,expected_error', [
    (True, 200, {}),
    (False, 401, {"fail": "login"})
])
def test_sample(is_admin, expected_status_code, expected_data):
    # do your setup
    if is_admin:
        user =  create_super_user()
    else:
        user =  normal_user()

    # do your request
    response = client.get('something')

    # make assertion on response
    assert response.status_code == expected_status_code
    assert response.data == expected_data

您还可以具有多个参数层,例如:

@pytest.mark.parametrize('is_admin', [
    True,
    False
])
@pytest.mark.parametrize('some_condition,expected_status_code,expected_error', [
    (True, 200, {}),
    (False, 401, {"fail": "login"})
])

这将对is_admin(True / False)和其他参数的每个组合执行测试,很好吗?

pytest parametrize tests处查看文档

如果您不使用pytest,请检查该库是否执行类似Parameterized testing with any Python test framework

的操作