1

unittest 带有许多断言方法。我对使用内置 Pythonassert和比较运算符与内置的简单 unittest 断言进行了 timeit 测试。

#!/usr/bin/python
import timeit

s = """\
import unittest
class TestRepomanManExtFunctions(unittest.TestCase):
    def test1(self):
        someObj = object()
        newObj = someObj
        self.assertEqual(someObj, newObj)

    def test2(self):
        str1 = '11111111111111111111111111111111111111'
        str2 = '33333333333333333333333333333333333333'
        self.assertNotEqual(str1, str2)


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

"""
t = timeit.Timer(stmt=s)
print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)

s2 = """\
import unittest
class TestRepomanManExtFunctions(unittest.TestCase):
    def test1(self):
        someObj = object()
        newObj = someObj
        assert someObj == newObj

    def test2(self):
        str1 = '11111111111111111111111111111111111111'
        str2 = '33333333333333333333333333333333333333'
        assert str1 != str2


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

"""

t = timeit.Timer(stmt=s2)
print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)

结果是

yeukhon@yeukhon-P5E-VM-DO:/tests$ python t.py
1203.46 usec/pass
873.06 usec/pass
yeukhon@yeukhon-P5E-VM-DO:tests$ vim t.py
yeukhon@yeukhon-P5E-VM-DO:tests$ python t.py
1300.33 usec/pass
956.35 usec/pass
yeukhon@yeukhon-P5E-VM-DO:tests$ python t.py
1208.82 usec/pass
865.18 usec/pass

使用 unittest 的内置断言方法的一个优点是它告诉用户实际比较的是什么。我实际测试的一个例子:

======================================================================
FAIL: test_000_write_to_file_directory_not_exist (__main__.TestRepomanManExtFunctions)
Test writing content to a new file whose parent directory
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/mock.py", line 1224, in patched
    return func(*args, **keywargs)
  File "test_ext.py", line 71, in test_000_write_to_file_directory_not_exist
    self.assertNotEqual(mk_exists.call_args_list, exists_call_list)
AssertionError: [call('/tmp/test/fake/')] == [call('/tmp/test/fake/')]

这里使用简单assert X = Y

======================================================================
FAIL: test_000_write_to_file_directory_not_exist (__main__.TestRepomanManExtFunctions)
Test writing content to a new file whose parent directory
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/mock.py", line 1224, in patched
    return func(*args, **keywargs)
  File "test_ext.py", line 72, in test_000_write_to_file_directory_not_exist
    assert exists_call_list != mk_exists.call_args_list
AssertionError

除了这个优势,我们还可以利用内置的self.assert_*(...).

为什么原始速度更快?我知道访问属性和检查类通常比较慢。但是我也想知道是怎么回事?我希望这是一个有效的问题。

谢谢

4

2 回答 2

1

与内联执行的 assert 关键字相比,assert* 函数可能较慢,因为调用它(将参数推送到堆栈、调用、从堆栈中弹出返回地址等)存在开销。如您所提到的,assert* 函数还有一些其他不错的属性,例如打印预期值和实际值。

您是出于好奇还是这是一个实际问题?看到断言速度成为瓶颈的任何情况,我都会感到惊讶。

于 2012-07-14T19:52:58.810 回答
0

在对您使用的单元测试库提供的断言进行单元测试时,会收集有关您的测试的更多信息。他们收集测试是成功还是失败、导致错误的原因、捕获抛出的任何异常以及测试的任何输出。然后将这个数据集合处理成您需要的任何输出,无论是标准输出还是 xml 文件。这一切都只需要时间并且需要大量的函数开销才能完成,其中单个断言或多或少是内联的,并显示错误以及文件和行号。

两人在幕后有着天壤之别。

于 2012-07-14T20:27:53.387 回答