【问题标题】:Python unittest: test a testPython unittest:测试一个测试
【发布时间】:2013-09-09 09:17:09
【问题描述】:

我正在编写一些适用于非常大和非常小的浮点数的代码(例如,1e-150 可能是一个有效的答案)。为了对此进行单元测试,我想将浮点数与一些有效数字而不是小数位进行比较,所以我有以下内容。

import unittest as ut
from numpy.testing import assert_approx_equal

class newTestCase(ut.TestCase):
"""Extends the basic unittest TestCase."""

def assertSFAlmostEqual(self, a, b, places=7):
    """Uses numpy to test if two floats are the same but to a defined
    number of significant figures rather than decimal places.

    Args:
        a: float to be compared
        b: float to be compared
        places: number of significant figures to match. unittest default
        for assertAlmostEqual is 7, so 7 is the default here
    """
    if isinstance(a, float) != True or isinstance(b, float) != True:
        raise TypeError

    raised = False
    try:
        assert_approx_equal(a, b, significant=places)
    except:
        raised = True
    self.assertFalse(raised, "FLoats %g and %g are not equal to %i "
                     "significant figures" % (a, b, places))

这似乎工作正常,但我计划在很多地方使用它,所以我想确定它真的可以正常工作。我的问题是我怎样才能最明智地做到这一点?是否有适当的机制来对单元测试进行单元测试?

我在这里找到了可能的答案,

How to unittest unittest TestCases

但我不明白这是如何工作的。

提前非常感谢!

【问题讨论】:

    标签: python unit-testing floating-point


    【解决方案1】:

    unittest.TestCase 的子类类似于 any 其他类,因此您可以编写一个 unittest.TestCase 来检查其方法是否正常工作。

    特别是,您应该构建应该通过和失败测试的数对集合,然后使用这些输入调用 assertSFAlmostEqual 方法并查看测试是通过还是失败。

    您链接的答案就是这样做的,尽管它可能是一个比所需解决方案更复杂的解决方案。例如,我会简单地写如下内容:

    import unittest
    
    
    class MyBaseTestCase(unittest.TestCase):
        def assertSpec(self, thing):
            assert thing == 123
    
    
    class TestMyTest(MyBaseTestCase):
        def test_failures(self):
            self.assertRaises(AssertionError, self.assertSpec, 121)
    
        def test_successes(self):
            self.assertSpec(123)
    
    if __name__ == "__main__":
        unittest.main()
    

    您只需对测试用例进行子类化,所有测试只需使用您知道应该通过/不通过测试的特定参数调用您编写的assert* 方法。


    关于您当前实现 assert* 方法的一些说明:

    if isinstance(a, float) != True or isinstance(b, float) != True:
    

    避免与TrueFalse 进行比较。在你的情况下,你可以简单地写:

    if not isinstance(a, float) or not isinstance(b, float):
    # or:
    if not (isinstance(a, float) and isinstance(b, float))
    

    这也更容易阅读。

    raised = False
    try:
        assert_approx_equal(a, b, significant=places)
    except:
        raised = True
    

    从不使用普通的 except: 捕获异常。在这种情况下,您真的只想捕获由assert_approx_equal 提出的AssertionError,因此您应该使用:

    raised = False
    try:
        assert_approx_equal(a, b, significant=places)
    except AssertionError:
        raised = True
    

    其次,您可以避免使用raised 标志。 try-except 语句允许 else 子句仅在未引发异常时执行:

    try:
        assert_approx_equal(a, b, significant=places)
    except AssertionError:
        # here put the code to be executed when the assertion fails.
    else:
        # here put the code to be executed when *no* exception was raised.
    

    【讨论】:

    • 非常感谢,效果很好。也感谢其他 cmets。
    【解决方案2】:

    一种方法是 TDD(测试驱动开发):

    1. 编写一个失败的测试。
    2. 让代码通过测试。
    3. 重构。
    4. 转到 1。

    这里的关键是先写一个失败的测试。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-04
      • 1970-01-01
      • 2014-08-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多