如何正确使用在单元测试中返回值的每次测试设置功能?

时间:2019-07-01 18:44:42

标签: python unit-testing python-unittest

对于unittest.TestCase套件中的每个测试,我需要进行一些设置:运行一个为每个测试返回不同值的函数(取决于每个测试的某些属性作为参数传递给设置功能)。

我可以使用一个setUp()钩子,但是它不返回值,也不接受参数。但是,在这种情况下,论点并不重要。

推荐什么策略?

  • 创建自定义设置功能以在每个测试用例中使用
  • 使用setUp()和全局变量
  • setUp()与类或实例变量一起使用

2 个答案:

答案 0 :(得分:1)

我遵循以下通用策略:如果将变量用于多个测试功能,则在setUp()中定义它。如果仅在特定功能局部使用该功能,请在该功能中进行定义。

采用以下示例:

说我在软件包program中有一个名为list_utils.py的python模块,在list_utils.py中我具有以下功能:

def list_to_string(mylist):
    """ Takes a list of strings and joins them into a single string.
    """
    return ' '.join(mylist)

def list_extender(mylist, extend_item):
    return mylist.extend(extend_item)

然后我通过指定mytestlist设置单元测试脚本,因为它将用于多种测试功能:

from program import list_utils as lu

class TestListUtils(unittest.TestCase):
    """
    A subclass of unittest to test list_utils.py
    """
    def setUp(self):
        self.mytestlist = ['Hi', 'there']

    def test_list_to_string(self):
        """
        Ensures my list is converted to string
        """
        self.assertTrue(isinstance(lu.list_to_string(self.mytestlist), string))
    def test_list_extender(self):
        """
        Ensures list is extended when argument is passed.
        """
        mylocalvariable = 'Adam'
        self.assertTrue(lu.list_extender(self.mytestlist, mylocalvariable)[-1] == 'Adam')

    def tearDown(self):
        pass

if __name__ == '__main__':
    unittest.main()

您看到对于list_extender,我传入了mylocalvariable,因为我只会在该函数的范围内使用它,但是mytestlist是在setUp中定义的,因为我使用了它多次。通过遵循这种通用方法,您不必过多地setUp膨胀,并且如果多次使用它们,也不必在每个特定的单元测试中重新实例化变量。

答案 1 :(得分:0)

请注意以下我在setup和Setup之间的定义:每个测试都必须进行一些设置活动,但是不一定要将它们放入Setup方法中。

我的喜好是每个测试功能应易于理解。我不想看测试代码,不知道“这个值突然从哪里来”之类的。这意味着,我避免使用常见的Setup方法,而是使用也具有描述性名称的辅助函数/方法。更准确地说:

  • 如果测试用例需要特定的设置,我通常将其直接嵌入到测试中。
  • 如果测试用例的子集具有相同或相似的设置,则考虑创建一个辅助方法来提取公共部分。该帮助程序方法的名称应具有描述性,例如makeTrafficLightInGreenState,用于帮助程序工厂生成特定类型的交通信号灯对象。在此示例中,我还可以将makeTrafficLightInRedState用于另一组测试。我发现这比常见的Setup方法更可取,后者只创建绿色和红色交通信号灯:最后,您会感到困惑,Setup的哪个部分与哪个测试有关。当然,在编写辅助方法时,您也可以随意给它们指定参数,这在交通信号灯示例中可能会导致“ makeTrafficLightInState(green)”。但是,在这里选择哪种方法是特定于情况的。
  • 即使 all 测试有一些共同点,例如创建某个对象,我还是更喜欢将其放在描述性命名的辅助方法中,而不是依赖于对Setup的隐式调用。
  • 有时我也使用Setup,但是仅用于不需要理解测试用例逻辑的活动。例如,如果有一些原始状态需要在测试用例开始时保留,然后再恢复,则可以将其放入Setup中,而对各个测试用例的可读性没有任何负面影响。

在您的情况下,您似乎已经具有一个函数,该函数的参数适合于交付特定于测试用例的数据。我只是从需要它的每个测试用例中调用该函数。或者,如果调用该函数并不简单(您必须创建其他对象作为其参数等),则再次将其放入帮助器方法中。