unittest comes with many assert methods. I did a timeit test on using built-in Python assert and comparison operator vs built-in simple unittest assertion.
#!/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)
The results are
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
One advantage of using the unittest’s built-in assert methods is that it tells the user what is actually being compared. An example from of my actual tests:
======================================================================
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/')]
Here is using simple 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
Besides this advantage, what other nice things can we do by utilising the built-in self.assert_*(...)?
Why is the raw faster? I know accessing attribute and checking against a class is generally slower. But I want to know what’s going on too? I hope this is a valid question.
Thanks
Probably the assert* function is slower because there is overhead in calling it (pushing parameters to stack, calling, popping return address from stack etc.), compared to the assert keyword which is executed inline. The assert* functions have some other nice properties as you have mentioned, like printing the expected and actual value.
Are you asking out of curiosity or is this an actual problem? I’d be surprised to see any situation where the speed of asserts is a bottleneck.