复杂数据结构上的python unittest.TestCase.assertEquals()

时间:2013-10-11 10:14:54

标签: python unit-testing testing rounding

我正在单元测试一个返回非常复杂数据结构的函数(集合列表列表等)。我手动验证了输出,现在我想确保在没有注意的情况下它不会改变。

现在我有:

   self.assertEquals(data,
        {'Instr1': {'COUPON_LIST': '0 % SEMI 30/360',
                    'LEGAL_ENTITY': 'LE_XS0181523803',
                    'MATURITY_DATE': '2014/12/31',
                    'scenarios': {'Base': {'Spread Over Yield': -1.9/100,
                                           'THEO/PV01': -1500.15,
                                           'THEO/Value': 0.333,
                                           'THEO/Yield': 3.3/100},
                                  'UP': {'Spread Over Yield': -2.2/100,
                                         'THEO/PV01': -1000.1,
                                         'THEO/Value': 0.111,
                                         'THEO/Yield': 5.5/100}}},
         'Instr2': {'COUPON_LIST': None,
                    'LEGAL_ENTITY': 'LE_US059512AJ22',
                    'MATURITY_DATE': '2014/12/31',
                    'scenarios': {'Base': {'Spread Over Yield': None,
                                           'THEO/PV01': None,
                                           'THEO/Value': 1.0,
                                           'THEO/Yield': 0.0},
                                  'UP': {'Spread Over Yield': None,
                                         'THEO/PV01': -15.15,
                                         'THEO/Value': 4055.344,
                                         'THEO/Yield': 4.4/100}}},
         'Instr3': {'COUPON_LIST': '0 % SEMI 30/360',
                    'LEGAL_ENTITY': 'LE_XS0181523803',
                    'MATURITY_DATE': '2014/12/31',
                    'scenarios': {'Base': {'Spread Over Yield': -1.9/100,
                                           'THEO/PV01': -1500.15,
                                           'THEO/Value': 0.333,
                                           'THEO/Yield': 3.3/100},
                                  'UP': {'Spread Over Yield': -2.2/100,
                                         'THEO/PV01': -1000.1,
                                         'THEO/Value': 0.111,
                                         'THEO/Yield': 5.5/100}}},
         'Instr4': {'COUPON_LIST': None,
                    'LEGAL_ENTITY': 'LE_US059512AJ22',
                    'MATURITY_DATE': '2014/12/31',
                    'scenarios': {'Base': {'Spread Over Yield': None,
                                           'THEO/PV01': None,
                                           'THEO/Value': 1.0,
                                           'THEO/Yield': 0.0},
                                  'UP': {'Spread Over Yield': None,
                                         'THEO/PV01': -15.15,
                                         'THEO/Value': 4055.344,
                                         'THEO/Yield': 4.4/100}}}}

我有两个问题:

  1. 测试类不稳定且数据可能发生变化。在这种情况下,我想快速查明输出更改的位置,并仅验证差异。例如。我正在寻找一个很好的输出说

    data ['Instr1'] ['MATURITY_DATE']:'2014/12/31'!= '31 / 12/2014'

    data ['Instr5']:在lhs中找不到节点

    但同时我不想手动测试结构的每个节点。

  2. 你可以看到一些元素是浮点数,而4.4 / 100!= 0.044。我需要在float节点上运行AssertAlmostEqual的逻辑,在其他所有节点上运行AssertEqual。

  3. 有没有这样做的图书馆,还是我必须自己编写?

2 个答案:

答案 0 :(得分:1)

快速而肮脏的解决方案是使用difflib比较数据的漂亮表示。但是这个解决方案绝对不是健壮的:

In [22]: import copy
    ...: import difflib
    ...: import pprint
    ...:
In [23]: data = {'Instr1': {'COUPON_LIST': '0 % SEMI 30/360',
    ...:                     'LEGAL_ENTITY': 'LE_XS0181523803',
    ...:                     'MATURITY_DATE': '2014/12/31',
    ...:                     'scenarios': {'Base': {'Spread Over Yield': -1.9/100,
    ...:                                            'THEO/PV01': -1500.15,
    ...:                                            'THEO/Value': 0.333,
    ...:                                            'THEO/Yield': 3.3/100},
    ...:                                   'UP': {'Spread Over Yield': -2.2/100,
    ...:                                          'THEO/PV01': -1000.1,
    ...:                                          'THEO/Value': 0.111,
    ...:                                          'THEO/Yield': 5.5/100}}},
    ...:          'Instr2': {'COUPON_LIST': None,
    ...:                     'LEGAL_ENTITY': 'LE_US059512AJ22',
    ...:                     'MATURITY_DATE': '2014/12/31',
    ...:                     'scenarios': {'Base': {'Spread Over Yield': None,
    ...:                                            'THEO/PV01': None,
    ...:                                            'THEO/Value': 1.0,
    ...:                                            'THEO/Yield': 0.0},
    ...:                                   'UP': {'Spread Over Yield': None,
    ...:                                          'THEO/PV01': -15.15,
    ...:                                          'THEO/Value': 4055.344,
    ...:                                          'THEO/Yield': 4.4/100}}},
    ...:          'Instr3': {'COUPON_LIST': '0 % SEMI 30/360',
    ...:                     'LEGAL_ENTITY': 'LE_XS0181523803',
    ...:                     'MATURITY_DATE': '2014/12/31',
    ...:                     'scenarios': {'Base': {'Spread Over Yield': -1.9/100,
    ...:                                            'THEO/PV01': -1500.15,
    ...:                                            'THEO/Value': 0.333,
    ...:                                            'THEO/Yield': 3.3/100},
    ...:                                   'UP': {'Spread Over Yield': -2.2/100,
    ...:                                          'THEO/PV01': -1000.1,
    ...:                                          'THEO/Value': 0.111,
    ...:                                          'THEO/Yield': 5.5/100}}},
    ...:          'Instr4': {'COUPON_LIST': None,
    ...:                     'LEGAL_ENTITY': 'LE_US059512AJ22',
    ...:                     'MATURITY_DATE': '2014/12/31',
    ...:                     'scenarios': {'Base': {'Spread Over Yield': None,
    ...:                                            'THEO/PV01': None,
    ...:                                            'THEO/Value': 1.0,
    ...:                                            'THEO/Yield': 0.0},
    ...:                                   'UP': {'Spread Over Yield': None,
    ...:                                          'THEO/PV01': -15.15,
    ...:                                          'THEO/Value': 4055.344,
    ...:                                          'THEO/Yield': 4.4/100}}}}

In [24]: data_repr = pprint.pformat(data)

In [25]: data2 = copy.deepcopy(data)

In [26]: data2['Instr1']['MATURITY_DATE'] = '31/12/2014'

In [27]: data2_repr = pprint.pformat(data2)

In [28]: def get_diff(a, b):
    ...:     differ = difflib.unified_diff(a.splitlines(True), b.splitlines(True))
    ...:     return ''.join(line for line in differ if not line.startswith(' '))

In [29]: print(get_diff(data_repr, data2_repr))
--- 
+++ 
@@ -1,6 +1,6 @@
-            'MATURITY_DATE': '2014/12/31',
+            'MATURITY_DATE': '31/12/2014',

然而,这并不能解决浮点数问题。您可以使用简单的递归函数首先将float点值替换为round ed值到某个有效数字来解决此问题。

据我所知,没有这样的库允许对比较进行这种精细控制,所以如果你想要一个强大的解决方案,你最好自己编写整个代码。

我还要指出,也许你应该将这个数据结构重构为更结构化的类,这会使事情变得更容易。

最后但并非最不重要:在比较unittest时,您可以使用TestCase的{​​{3}}来确保assertAlmostEqual来电float,而不会这样做用手。


现在我考虑一下,您可以使用addTypeEqualityFunc执行dict的自定义比较,这可以添加有关不匹配的更多信息。要查找所有不匹配您必须在自定义函数中使用一些except AssertionError as e:块,请始终检查所有子元素,然后以某种方式“加入”错误消息。但我不认为解决方案会如此干净。

答案 1 :(得分:0)

我会编写一个具有预期参数和参数的函数来单独测试和教授结构中的每个项目。然后,您可以提供适合要测试的项目的错误说明。

对于上面的复杂结构,写下多个这样的函数,每个'深度'一个。

E.g。

AssertEqualData(DataToTest,expectedData)检查一个数据,调用AssertInstr

AssertEqualInstr(InstrToTest,expectedInstr)检查一个'InstrX'元素,该元素为每个项调用AssertEqualYield

检查一个Base或UP元素的AssertEqualYield(yieldToTest,expectedYield)

断言Base和Up项目的AssertEqualScenario(scenarioToTest,expectedScenario)。