如何对比两个嵌套数据结构以进行单元测试?

7 投票
2 回答
2238 浏览
提问于 2025-04-17 15:30

对于那些了解perl的人,我在找一个类似于Test::Deep::is_deeply()的东西在Python中。

Python的unittest中,我可以方便地比较嵌套的数据结构,如果我期望它们是相等的:

self.assertEqual(os.walk('some_path'),
                 my.walk('some_path'),
                 "compare os.walk with my own implementation")

不过,在我想要的测试中,os.walk元组中各个子列表的文件顺序并不重要。

如果只是这个单一的测试,写个简单的解决方案也没问题。但我想象中会有多个测试,涉及到不同结构的嵌套数据。我希望能有一个通用的解决方案。

我查看了Python自己的unittest文档,还看了pyUnitnose及其插件。活跃的维护也是使用时一个重要的考虑因素。

我最终的目标是希望有一组描述性类型,比如UnorderedIterableSubsetOfSupersetOf等,可以用来描述一个嵌套的数据结构,然后利用这个描述来比较两个实际的数据集。

在os.walk的例子中,我想要的类似于:

comparison = OrderedIterable(
               OrderedIterable(
                 str,
                 UnorderedIterable(),
                 UnorderedIterable()
               )
             )

上面的内容描述了list(os.walk())会返回的数据结构。为了在单元测试中比较数据A和数据B,当前的路径名称会被转换成str(),然后目录和文件列表会被比较,忽略顺序,使用:

self.assertDeep(A, B, comparison, msg)

有没有这样的东西呢?还是说这是一项微不足道的任务,以至于人们自己写?我觉得自己能做到,但我不想重新发明轮子,尤其是不想编写完整的正交类型集合、测试等等。简而言之,我不会发布它,这样下一个人又得重新写一遍……

2 个回答

1

这不是一个解决方案,而是目前为了解决问题中提到的特定例子而采用的临时办法:

    os_walk = list(os.walk('some_path'))
    dt_walk = list(my.walk('some_path'))
    self.assertEqual(len(dt_walk), len(os_walk), "walk() same length")
    for ((osw, osw_dirs, osw_files), (dt, dt_dirs, dt_files)) in zip(os_walk, dt_walk):
        self.assertEqual(dt, osw, "walk() currentdir")
        self.assertSameElements(dt_dirs, osw_dirs, "walk() dirlist")
        self.assertSameElements(dt_files, osw_files, "walk() fileList")

从这个例子中,我们可以看到代码量其实挺多的。同时,我们也能发现,Python的unittest工具已经具备了大部分所需的功能。

5

Python Deep 这个项目看起来是为了重新实现 perl 语言中的 Test::Deep。这个项目的作者正是 Test::Deep 的原作者。最后一次更新是在2016年初。

更新(2018年8月):最新的版本(2016年2月)可以在 PyPi/Deep 找到。

我在 GitHub 上做了一些 P3k 的移植工作

撰写回答