重用代码进行方法更改的单元测试代码

时间:2017-11-19 17:52:24

标签: python unit-testing

我知道标题非常糟糕,但我想不出一个更有说服力的陈述问题的方式。我有很多单元测试:

 def test_send_new_registration_email(self):
    emails = NewEmail(email_client=MagicMock())
    emails.send_email = MagicMock()
    emails.send_marketing_email(recipients(), new_registration_payload())
    emails.send_email.assert_called_with(new_registration_output())

  def test_send_new_comment_email(self):
    emails = NewEmail(email_client=MagicMock())
    emails.send_email = MagicMock()
    emails.send_marketing_email(recipients(), new_registration_payload())
    emails.send_email.assert_called_with(new_comment_output())

这些单元测试中有20个。所有都遵循非常相似的模式基本上我将输入与所需输出进行比较。必须有一种方法来获得输入列表和输出列表并进行比较。

我可以做一个for循环,例如

def test_send_new_registration_email(self):
    for index, input in enum(inputs):
        emails = NewEmail(email_client=MagicMock())
        emails.send_email = MagicMock()
        emails.send_marketing_email(input)
        emails.send_email.assert_called_with(output[index])

然而,有更清洁的方法吗?

1 个答案:

答案 0 :(得分:1)

您正在寻找参数化测试。但是,实际实现取决于您用于单元测试的库。 vanilla unittest不提供任何参数化支持,因此您需要安装第三方软件包。 parameterizedpip install parameterized)的示例:

from parameterized import parameterized

@parameterized.expand([
    ((recipients(), new_registration_payload(), ), new_registration_output(), ),
    ((recipients(), new_registration_payload(), ), new_comment_output(), ),
])
def test_send_new_comment_email(self, input, output):
    emails = NewEmail(email_client=MagicMock())
    emails.send_email = MagicMock()
    emails.send_marketing_email(*input)
    emails.send_email.assert_called_with(output)

现在,在提供两个测试输入的情况下,测试将执行两次。

如果您打算使用pytest编写和运行测试(这是我自己使用的),它已经提供了开箱即用的测试参数化:

import pytest

data = [
    ((recipients(), new_registration_payload(), ), new_registration_output(), ),
    ((recipients(), new_registration_payload(), ), new_comment_output(), ),
]

@pytest.mark.parametrize("input, output", data)
def test_send_new_comment_email(input, output):
    emails = NewEmail(email_client=MagicMock())
    emails.send_email = MagicMock()
    emails.send_marketing_email(*input)
    emails.send_email.assert_called_with(output)

测试将运行两次:

$ pytest test_foo.py --collect-only

======== test session starts ========
platform darwin -- Python 3.6.3, pytest-3.2.5, py-1.5.2, pluggy-0.4.0
rootdir: /private/tmp, inifile:
plugins: mock-1.6.3, cov-2.5.1
collected 2 items                                                                                                                                                                          

<Module 'test_foo.py'>
    <Function 'test_send_new_comment_email[input0-registration_output]'>
    <Function 'test_send_new_comment_email[input1-comment_output]'>

======== no tests ran in 0.01 seconds ========