代码之家  ›  专栏  ›  技术社区  ›  Denilson Sá Maia

非关键单元测试失败

  •  4
  • Denilson Sá Maia  · 技术社区  · 15 年前

    我正在使用python的内置 unittest 模块和我想编写一些不重要的测试。

    我的意思是,如果我的程序通过了这样的测试,那就太好了!但是,如果它不通过,这不是一个真正的问题,程序仍然可以工作。

    例如,我的程序设计为使用自定义类型“A”。如果它不能和“A”一起工作,那么它就坏了。然而,为了方便起见,大部分的代码也应该与另一个类型的“B”一起使用,但这不是强制的。如果它不能与“B”一起工作,那么它就不会损坏(因为它仍然与“A”一起工作,这是它的主要目的)。不与“B”合作并不重要,我只会错过一个我可以拥有的“奖金功能”。

    另一个(假设的)例子是编写OCR时。算法应该能够识别测试中的大多数图像,但是如果其中一些图像失败了,也没关系。(不,我不写OCR)

    有没有办法在UnitTest(或其他测试框架)中编写非关键测试?

    10 回复  |  直到 13 年前
        1
  •  7
  •   Paul McMillan    13 年前

    实际上,在这种情况下,我可能会使用print语句来表示失败。更正确的解决方案是使用警告:

    http://docs.python.org/library/warnings.html

    但是,您可以使用日志记录工具生成更详细的测试结果记录(即,将“B”类失败设置为将警告写入日志)。

    http://docs.python.org/library/logging.html

    编辑:

    我们在Django中处理这个问题的方法是,我们有一些预期会失败的测试,还有一些基于环境跳过的测试。由于我们通常可以预测一个测试应该失败还是通过(即,如果我们不能导入某个模块,系统没有它,因此测试将无法工作),因此我们可以智能地跳过失败的测试。这意味着我们仍然运行将通过的每个测试,并且没有“可能”通过的测试。当单元测试可以预见地做一些事情时,它们是最有用的,并且能够在我们运行测试之前检测测试是否应该通过,这使得这成为可能。

        2
  •  4
  •   Guilherme Chapiewski    15 年前

    单元测试中的断言是二进制的:它们将工作或失败,没有中期。

    鉴于此,要创建那些“非关键”测试,当您不希望测试失败时,不应使用断言。你应该小心地这样做,这样你就不会损害测试的“有用性”。

    我对您的OCR示例的建议是,您可以使用一些东西在测试代码中记录成功率,然后创建一个断言,例如:“断言成功率”>8.5“,这将产生您想要的效果。

        3
  •  3
  •   ryber    15 年前

    我不完全确定UnitTest是如何工作的,但是大多数单元测试框架都有类似于类别的东西。我想您可以对这些测试进行分类,将它们标记为被忽略,然后仅当您对它们感兴趣时才运行它们。但是我从经验中知道,忽略的测试很快就会变成……只是忽略了没有人运行过的测试,因此写这些测试是浪费时间和精力的。

    我的建议是让你的应用去做,或者不去做,没有尝试。

        4
  •  3
  •   Wim Coenen    15 年前

    unittest 链接的文档:

    这里没有unittest.main(),而是 使用 控制水平越高,越短 输出,无需运行 从命令行。例如, 最后两行可以替换 用:

    suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)
    unittest.TextTestRunner(verbosity=2).run(suite)
    

    在您的情况下,可以创建单独的 TestSuite 关键测试和非关键测试的实例。可以使用命令行参数控制传递给测试运行程序的套件。测试套件还可以包含其他测试套件,这样您可以根据需要创建大型层次结构。

        5
  •  2
  •   Denilson Sá Maia    7 年前

    谢谢你的回答。不是只有一个答案很完整,所以我在这里写 a combination of all answers that helped me . 如果你喜欢这个答案,请投票选出负责这个问题的人。

    结论

    单元测试(或至少单元测试 unittest 模块)是二进制的。AS Guilherme Chapiewski says : 他们要么工作要么失败,没有中期。

    因此,我的结论是单元测试并不是这个工作的正确工具。似乎单元测试更关心 “保持一切正常运行,不会出现故障” 因此,我不能(也不容易)进行非二进制测试。

    因此,如果我试图改进一个算法或实现,那么单元测试似乎不是正确的工具,因为单元测试不能告诉我一个版本与另一个版本相比有多好(假设两个版本都正确实现了,那么两个版本都将通过所有单元测试)。

    我的最终解决方案

    我的最终解决方案基于 ryber's idea 代码显示在 wcoenen answer . 我基本上是在延长违约期限 TextTestRunner 让它不那么冗长。然后,我的主代码调用两个测试套件:使用标准的关键测试套件 文字特长 以及非关键的版本,我自己的版本不那么冗长。

    class _TerseTextTestResult(unittest._TextTestResult):
        def printErrorList(self, flavour, errors):
            for test, err in errors:
                #self.stream.writeln(self.separator1)
                self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
                #self.stream.writeln(self.separator2)
                #self.stream.writeln("%s" % err)
    
    
    class TerseTextTestRunner(unittest.TextTestRunner):
        def _makeResult(self):
            return _TerseTextTestResult(self.stream, self.descriptions, self.verbosity)
    
    
    if __name__ == '__main__':
        sys.stderr.write("Running non-critical tests:\n")
        non_critical_suite = unittest.TestLoader().loadTestsFromTestCase(TestSomethingNonCritical)
        TerseTextTestRunner(verbosity=1).run(non_critical_suite)
    
        sys.stderr.write("\n")
    
        sys.stderr.write("Running CRITICAL tests:\n")
        suite = unittest.TestLoader().loadTestsFromTestCase(TestEverythingImportant)
        unittest.TextTestRunner(verbosity=1).run(suite)
    

    可能的改进

    知道是否有任何带有非二进制测试的测试框架仍然很有用,比如 Kathy Van Stone suggested . 也许我不会用这个简单的个人项目,但它可能对未来的项目有用。

        6
  •  2
  •   Denilson Sá Maia    14 年前

    python 2.7(和3.1)增加了对跳过一些测试方法或测试用例的支持,并将一些测试标记为 预期故障 .

    http://docs.python.org/library/unittest.html#skipping-tests-and-expected-failures

    标记为预期失败的测试将不会被视为测试结果的失败。

        7
  •  1
  •   Kathy Van Stone    15 年前

    有些测试系统允许警告而不是失败,但是测试单元不是其中的一个(我不知道是哪一个,直接),除非您想扩展它(这是可能的)。

    您可以进行测试,以便它们记录警告而不是失败。

    处理这一问题的另一种方法是分离测试,只运行它们来获取通过/失败报告,而不具有任何构建依赖性(这取决于您的构建设置)。

        8
  •  0
  •   GHZ    15 年前

    看看鼻子: http://somethingaboutorange.com/mrl/projects/nose/0.11.1/

    有许多用于选择要运行的测试的命令行选项,您可以保留现有的UnitTest测试。

        9
  •  0
  •   Jonathanb    15 年前

    另一种可能性是创建一个“B”分支(您使用的是某种版本控制,对吗?)让你的“B”单元测试在那里。这样,您就可以保持发布版本的单元测试的干净(看,所有点!),但是仍然有对b的测试。如果您使用的是像git或mercurial这样的现代版本控制系统(我偏爱mercurial),那么分支/克隆和合并都是很简单的操作,所以我建议您这样做。

    不过,我认为你是在用测试来做他们不该做的事情。真正的问题是“B对你有多重要?”因为您的测试套件中应该只有您关心它们是否通过的测试。测试如果失败,则表示代码已损坏。这就是为什么我建议只在“B”分支中测试“B”,因为这将是开发“B”特性的分支。

    如果您愿意,可以使用记录器或打印命令进行测试。但是,如果你不太在意它被破坏而在你的单元测试中被标记出来,我会严肃地质疑你是否足够在意去测试它。此外,这增加了不必要的复杂性(设置调试级别的额外变量、完全独立于彼此但在同一空间内操作的多个测试向量,导致潜在的冲突和错误等)。除非你正在发展一个“你好,世界!”应用程序,我怀疑你的问题集足够复杂,没有添加额外的,不必要的复杂。

        10
  •  -1
  •   pero    15 年前

    你可以编写你的测试,以便他们计算成功率。 使用OCR,您可以抛出代码1000图像,并要求95%是成功的。

    如果您的程序必须使用A类型,那么如果失败,测试将失败。如果不需要和B一起工作,那么做这样的测试有什么价值呢?