等価性unittest.TestCase.assertEqual
をテストするために示す動作を正確に使用して、セットをチェックするクラスを作成したいと考えています。set
どの要素が最初のセットにのみ含まれ、どの要素が 2 番目のセットにのみ含まれるかを示す適切なメッセージが自動的に出力されます。
同様の動作を実装できることはわかっていますが、それはすでに でうまく行われているので、それ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)
unittest
私の環境では、Python ソース コードを含むディレクトリは読み取り専用であるため、ステートメントを追加しpdb
たり、print
ステートメントを追加したりして、この時点で何が失敗したtestCaseClass
かを確認することはできません。testCaseNames
__init__
しかし、どのメソッドにも必要な引数を提供できていないコード内の場所は見当たりません__init__
。これは、ユニット テスト用に実行されるファイル内でunittest
クラス ( ) をインポートしてインスタンス化するという事実と、継承するクラスを使用した舞台裏の魔法と関係があるのではないかと考えています。SetChecker
たぶん、から継承する既存の名前空間内のすべてのクラスをチェックしますTestCase
か? もしそうなら、ユニットテストをどのようにユニットテストしますか?
また、最初にSetChecker
継承元を作成し、ミックスインのようobject
に使用しようとしTestCase
ましたが、多くの MRO エラーが発生し、価値があるよりも頭痛の種に思えました。
__init__
これを検索してみましたが、検索するのが難しいエラーです (引数に関する単純な問題ではないように見えるため)。