我想编写一个类来检查集合,该类完全使用unittest.TestCase.assertEqual
测试set
相等性所表现出的行为。它会自动打印一条很好的消息,说明哪些元素仅在第一组中,哪些仅在第二组中。
我意识到我可以实现类似的行为,但由于它已经很好地完成了unittest.TestCase.assertEqual
,我宁愿只利用它(所以请不要回答说无用且已经很明显(但在这种情况下不适用)的建议“不要解决这与unittest.TestCase
“)
这是我的SetChecker
课程代码:
import unittest
class SetChecker(unittest.TestCase):
"""
SetChecker(set1, set2) creates a set checker from the two passed Python set
objects. Printing the SetChecker uses unittest.TestCase.assertEqual to test
if the sets are equal and automatically reveal the elements that are in one
set but not the other if they are unequal. This provides an efficient way
to detect differences in possibly large set objects. Note that this is not
a unittest object, just a wrapper to gain access to the helpful behavior of
unittest.TestCase.assertEqual when used on sets.
"""
EQUAL_MSG = "The two sets are equivalent."
def __init__(self, set1, set2, *args, **kwargs):
assert isinstance(set1, set)
assert isinstance(set2, set)
super(self.__class__, self).__init__(*args, **kwargs)
try:
self.assertEqual(set1, set2)
self._str = self.EQUAL_MSG
self._str_lines = [self._str]
self._indxs = None
except AssertionError, e:
self._str = str(e)
self._str_lines = self._str.split('\n')
# Find the locations where a line starts with 'Items '.
# This is the fixed behavior of unittest.TestCase.
self._indxs = [i for i,y in enumerate(self._str_lines)
if y.startswith('Items ')]
def __repr__(self):
"""
Convert SetChecker object into a string to be printed.
"""
return self._str
__str__ = __repr__ # Ensure that `print` and __repr__ do the same thing.
def runTest(self):
"""
Required by any sub-class of unittest.TestCase. Solely used to inherit
from TestCase and is not implemented for any behavior.
"""
pass
def in_first_set_only(self):
"""
Return a list of the items reported to exist only in the first set. If
the sets are equivalent, returns a string saying so.
"""
return (set(self._str_lines[1:self._indxs[1]])
if self._indxs is not None else self.EQUAL_MSG)
def in_second_set_only(self):
"""
Return a list of the items reported to exist only in the second set. If
the sets are equivalent, returns a string saying so.
"""
return (set(self._str_lines[1+self._indxs[1]:])
if self._indxs is not None else self.EQUAL_MSG)
当我在 IPython 中使用它时,这很好用:
In [1]: from util.SetChecker import SetChecker
In [2]: sc = SetChecker(set([1,2,3, 'a']), set([2,3,4, 'b']))
In [3]: sc
Out[3]:
Items in the first set but not the second:
'a'
1
Items in the second set but not the first:
'b'
4
In [4]: print sc
Items in the first set but not the second:
'a'
1
Items in the second set but not the first:
'b'
4
In [5]: sc.in_first_set_only()
Out[5]: set(["'a'", '1'])
In [6]: sc.in_second_set_only()
Out[6]: set(["'b'", '4'])
但是现在我也想为这个类编写单元测试。所以我做了一个TestSetChecker
类。这是该代码:
from util.SetChecker import SetChecker
class TestSetChecker(unittest.TestCase):
"""
Test class for providing efficient comparison and printing of
the difference between to sets.
"""
def setUp(self):
"""
Create examples for testing.
"""
self.set1 = set([1, 2, 3, 'a'])
self.set2 = set([2, 3, 4, 'b'])
self.set3 = set([1,2])
self.set4 = set([1,2])
self.bad_arg = [1,2]
self.expected_first = set(['1', 'a'])
self.expected_second = set(['4', 'b'])
self.expected_equal_message = SetChecker.EQUAL_MSG
self.expected_print_string = (
"Items in the first set but not the second:\n'a'\n1\n"
"Items in the second set but not the first:\n'b'\n4")
def test_init(self):
"""
Test constructor, assertions on args, and that instance is of proper
type and has expected attrs.
"""
s = SetChecker(self.set1, self.set2)
self.assertIsInstance(s, SetChecker)
self.assertTrue(hasattr(s, "_str"))
self.assertTrue(hasattr(s, "_str_lines"))
self.assertTrue(hasattr(s, "_indxs"))
self.assertEqual(s.__repr__, s.__str__)
self.assertRaises(AssertionError, s, *(self.bad_arg, self.set1))
def test_repr(self):
"""
Test that self-printing is correct.
"""
s1 = SetChecker(self.set1, self.set2)
s2 = SetChecker(self.set3, self.set4)
self.assertEqual(str(s1), self.expected_print_string)
self.assertEqual(str(s2), self.expected_equal_message)
def test_print(self):
"""
Test that calling `print` on SetChecker is correct.
"""
s1 = SetChecker(self.set1, self.set2)
s2 = SetChecker(self.set3, self.set4)
s1_print_output = s1.__str__()
s2_print_output = s2.__str__()
self.assertEqual(s1_print_output, self.expected_print_string)
self.assertEqual(s2_print_output, self.expected_equal_message)
def test_in_first_set_only(self):
"""
Test that method gives list of set elements found only in first set.
"""
s1 = SetChecker(self.set1, self.set2)
s2 = SetChecker(self.set3, self.set4)
fs1 = s1.in_first_set_only()
fs2 = s2.in_first_set_only()
self.assertEqual(fs1, self.expected_first)
self.assertEqual(fs2, self.expected_equal_message)
def test_in_second_set_only(self):
"""
Test that method gives list of set elements found only in second set.
"""
s1 = SetChecker(self.set1, self.set2)
s2 = SetChecker(self.set3, self.set4)
ss1 = s1.in_second_set_only()
ss2 = s2.in_second_set_only()
self.assertEqual(ss1, self.expected_second)
self.assertEqual(ss2, self.expected_equal_message)
if __name__ == "__main__":
unittest.main()
据我所知,TestSetChecker
它与我编写的许多其他单元测试类没有区别(除了它正在测试的特定功能)。
然而,__init__
当我尝试执行包含单元测试的文件时,我看到了一个非常不寻常的错误:
EMS@computer ~/project_dir/test $ python TestSetChecker.py
Traceback (most recent call last):
File "TestSetChecker.py", line 84, in <module>
unittest.main()
File "/opt/python2.7/lib/python2.7/unittest/main.py", line 94, in __init__
self.parseArgs(argv)
File "/opt/python2.7/lib/python2.7/unittest/main.py", line 149, in parseArgs
self.createTests()
File "/opt/python2.7/lib/python2.7/unittest/main.py", line 155, in createTests
self.test = self.testLoader.loadTestsFromModule(self.module)
File "/opt/python2.7/lib/python2.7/unittest/loader.py", line 65, in loadTestsFromModule
tests.append(self.loadTestsFromTestCase(obj))
File "/opt/python2.7/lib/python2.7/unittest/loader.py", line 56, in loadTestsFromTestCase
loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
TypeError: __init__() takes at least 3 arguments (2 given)
包含 Pythonunittest
源代码的目录在我的环境中是只读的,因此我无法在其中添加pdb
甚至print
语句来查看此时某些失败的内容testCaseClass
或内容。testCaseNames
__init__
但是我在我的代码中看不到任何地方我未能为任何__init__
方法提供所需的参数。我想知道这是否与某些幕后魔术有关,这些魔术与继承自的类unittest
以及我在SetChecker
要为单元测试执行的文件中导入和实例化一个类 () 的事实有关。
也许它会检查现有命名空间中继承自的所有类TestCase
?如果是这样,您如何对单元测试进行单元测试?
我还尝试先从SetChecker
继承object
并尝试TestCase
像混合一样使用,但这会产生很多 MRO 错误,而且看起来比它的价值更令人头疼。
我试过搜索这个,但搜索起来是一个困难的错误(因为它似乎不是一个简单的__init__
参数问题)。