1

我正在创建一个继承自NamedTuple(特别是为了不变性)的类,该类在元组中包含三段数据。我重写了__repr__()以提供一个漂亮的、人类可识别的类表示。然而,__repr__为了提供漂亮的表示,自定义必须对元组中的数据进行一些昂贵的计算。因此,我的__repr__功能按以下方式组织:

class MyClass(NamedTuple):
   data1: float
   data2: MyOtherClass
   data3: float


def __repr__():
    exp_1 = self.expensive_function1(self.data1, self.data2, self.data3)
    exp_2 = self.expensive_function2(self.data1, self.data2, self.data3)

    repr_component_1 = MyClass.static_func1(self.data1, exp_1, exp_2)
    repr_component_2 = MyClass.static_func2(self.data2, exp_1, exp_2)
    repr_component_3 = MyClass.static_func2(self.data3, exp_1, exp_2)

    return f"{repr_component_1} {repr_component_2}{repr_component_3}"

代码本身没有问题。它运行良好并且工作正常。我遇到的问题是如何有效地静态方法repr_component_1repr_component_2repr_component_3.

如果MyClass不是特别需要是不可变的,我可以投入私有类属性exp_1并且exp_2没有问题。但是,MyClass由于各种原因,它必须是不可变的。

问题是,exp_1并且exp_2特定于实例的结果,然后作为输入进入静态方法。

因此,我能想到的唯一测试方法(使用pytest)如下:

def test_repr_component_1():
    a = MyClass(data1, data2, data3)
    exp_1 = a.expensive_function1(self.data1, self.data2, self.data3)
    exp_2 = b.expensive_function2(self.data1, self.data2, self.data3)
    result1 = MyClass.static_func1(a.data1, exp_1, exp_2)
    assert result1 == "expected result"

但是,每个测试场景有很多行(我的实际代码超过五行)!当然,我希望测试许多场景。我以前听说过设置和拆卸的东西,但我不知道这些东西是否适用于这种情况。

想对编写这些单元测试的“专业”和pythonic方式有一些想法。

编辑:我确实想到使用 Python 3.7 dataclass(因为它能够被“冻结”),这将允许我在步骤期间设置exp_1exp_2作为私有属性,__post_init__但我计划将其设为公共库并且不想要不得不依赖只有 Python >= 3.7 的用户才能使其工作。

4

1 回答 1

1

在编写许多场景时,参数化将帮助您减少代码行数:

@pytest.mark.parametrize(
    ['data1', 'data2', 'data3', 'data_argument', 'static_func', 'expected_result'],
    [
        [ # scenario 1
            data1,
            data2,
            data3,
            data1, 
            MyClass.static_func1,
            'repr_component1'
        ],
        [ # scenario 2
            data1,
            data2,
            data3,
            data2, 
            MyClass.static_func2,
            'repr_component2'
        ]
    ]
)
def test_repr_component(data1, data2, data3, data_argument, static_func, expected_result):
    a = MyClass(data1, data2, data3) # two scenarios use the same code for tests
    exp_1 = a.expensive_function1(data1, data2, data3)
    exp_2 = a.expensive_function2(data1, data2, data3)
    result = static_func1(data_argument, exp_1, exp_2)
    assert result == expected_result
于 2019-05-16T17:30:15.770 回答