【问题标题】:Python unittest AssertionError not being raisedPython unittest AssertionError 未引发
【发布时间】:2023-03-09 20:55:01
【问题描述】:

我正在尝试为我的 python 包编写单元测试,但我发现当我运行测试时 AssertionErrors 没有被引发,当它们应该被引发时。这是一个 MWE:

在 exampleModule.py 我有:

#! /usr/bin/env python                                                                                                                                                          
import unittest

class UnitTest(unittest.TestCase):

    def runTest(self):
        print("Starting test...")
        a = 4
        b = 5
        self.assertEqual(a,b)
        print("TEST COMPLETE")
        return

在 testError.py 我有:

#! /usr/bin/env python                                                                                                                                                          
import unittest

class AllTests(unittest.TestCase):

    def testExample(self):
        from exampleModule import UnitTest
        UT = UnitTest()
        UT.run()
        return

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

当我运行 testError.py 时,我希望在 exampleModule.py 中看到 UnitTest 报告的 AssertionError,但是,我只看到以下内容:

> ./testError.py
Starting test...
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

为什么没有引发 AssertionError?如果我将 UnitTest() 类放在 testError.py 中(即,所有内容都在同一个文件中),则会引发 AssertionError。那么为什么当 UnitTest 存储在不同的文件中时不会引发错误呢?

谢谢!

【问题讨论】:

  • 谢谢@Gang——那么我在哪里调用assertRaises()?在我的 AllTests 课程中? TestCase.run() 调用是否返回了上下文管理器?如果我理解正确,UnitTest.runTest() 函数中出现的任何错误都会被忽略并简单地存储在上下文管理器中?在我的 UnitTest.runTest() 函数中查询上下文管理器只会创建另一个 AssertionError,它也被“忽略”。
  • 用另一个单元测试来测试一个单元测试是没有意义的。
  • @Gang -- 那么我将如何重构我的示例,以便我可以将单个测试存储在模块中,并拥有一个调用所有这些测试并使用 main() 函数运行它们的脚本?
  • 你是指nosetests还是nose2还是pytest,他们会发现并进行测试而不使用__main__

标签: python unit-testing assert python-unittest


【解决方案1】:

构造单元测试的约定是这样的:

将所有测试保存在tests 目录中。

测试模块将被命名为test_modulea.pyclass TestClassA

nosetests -vw tests 运行所有测试。

【讨论】:

    【解决方案2】:

    TestCase.run() 创建或更新 TestResult 对象,假设您打算对这些结果做一些有趣的事情。 但是你马上把它们扔掉:

        UT.run()
    

    任何失败或错误——包括引发的异常——都会出现在该结果对象中。 例如:

    def testExample(self):
        from exampleModule import UnitTest
        UT = UnitTest()
        result = UT.run()
        print('Errors:  {!r}'.format(result.errors))
        print('Failures:  {!r}'.format(result.failures))
        return
    

    打印出来:

    失败: [(, 'Traceback (最近一次调用最后一次):\n 文件“/home/kjc/tmp/exampleModule.py”, 第 11 行, 在 runTest\n self.assertEqual(a, b)\nAssertionError: 4 != 5\n')]

    它捕获各种异常,例如我在断言前添加sys.exit() 的示例:

    错误: [(, 'Traceback (last last call last):\n File "/home/kjc/tmp/exampleModule.py", line 11 , 在 runTest\n import sys; sys.exit()\nSystemExit\n')]

    作为记录,您的示例生成的一个通过测试是testExample 本身。 您可以通过在testExample 早期致电self.fail() 来验证这一点。 (正如一位评论员所说,单元测试调用单元测试是一件非常奇怪的事情。)

    一个解决方案

    您似乎想正常运行测试,但要从多个文件中运行。 如果是这样,您可以制作一堆典型的 unittest.main()-风格 测试模块,然后手动加载它们。 您的 test-everything 脚本将如下所示:

    #!/usr/bin/env python
    import unittest
    
    
    # Edit this to include new modules or TestCases to run.
    _NAMES = ['testmoda', 'testmodb']  # testothermodule.SomeTestCase, etc...
    
    
    def _main():
        suite = unittest.defaultTestLoader.loadTestsFromNames(_NAMES)
        unittest.TextTestRunner().run(suite)
        return  # WARNING: This always returns a successful exit value.
    
    
    if __name__ == '__main__':
        _main()
    

    您的测试模块将是通常的一个或多个TestCases,带有对unittest.main() 的条件调用,因此每个模块都可以独立运行:

    #!/usr/bin/env python
    import unittest
    
    
    class TestModA(unittest.TestCase):
    
        def testThatPasses(self):
            self.assertEqual(0, -0)
            return
    
        def testThatFails(self):
            self.assertEqual(0, float('inf'))
            return
    
        def testThatBlowsUp(self):
            raise RuntimeError('OMG!')
            return
    
    
    if '__main__' == __name__:
        unittest.main()
    

    如果这对您来说还不够繁琐,您还可以阅读 discover() method 或模块级 load_tests protocol.

    【讨论】:

    • 太棒了!感谢您的解释——我想我现在理解得更好了。也感谢您提出的解决方案!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-12
    • 1970-01-01
    • 1970-01-01
    • 2016-02-06
    • 2022-01-08
    • 1970-01-01
    • 2018-07-19
    相关资源
    最近更新 更多