2013-09-30 14 views
7

Tôi đang cố gắng tạo một khung kiểm tra đơn vị tùy chỉnh bằng cách phân loại lớp unittest.testcase nhưng dường như mắc lỗi khi xử lý phương thức __init__.quá tải unittest.testcase trong python

Tôi không thể hiểu tại sao hàm tạo của ComplexTest không được gọi trước một trong BasicTest và ngoại lệ cũng có vẻ liên quan đến các nhà xây dựng của tôi.

Tôi khá mới đối với Python nên mọi trợ giúp về cách giải quyết vấn đề cụ thể này hoặc các kiến ​​trúc thay thế cho trường hợp sử dụng của tôi sẽ được chào đón nhiều nhất.

Cảm ơn bạn!

1) test_framework.py

import unittest 

class BasicTest(unittest.TestCase): 
    def __init__(self, *args, **kwargs): 
     print('BasicTest.__init__') 
     super(unittest.TestCase, self).__init__(*args, **kwargs) 

    def setUp(self): 
     print('BasicTest.setUp') 
     super(unittest.TestCase, self).tearDown() 

    def tearDown(self): 
     print('BasicTest.tearDown') 
     super(unittest.TestCase, self).tearDown() 


class ComplexTest(BasicTest): 
    def __init__(self, *args, **kwargs): 
     print('ComplexTest.__init__') 
     super(BasicTest, self).__init__(*args, **kwargs) 

    def setUp(self): 
     print('ComplexTest.setUp') 
     super(BasicTest, self).tearDown() 

    def tearDown(self): 
     print('ComplexTest.tearDown') 
     super(BasicTest, self).tearDown() 

2) test.py

import unittest 
import test_framework 

class TestValueFunctions(test_framework.ComplexTest): 
    def __init__(self, *args, **kwargs): 
     print('TestValueFunctions.__init__') 
     super(test_framework.ComplexTest, self).__init__(*args, **kwargs) 

    def setUp(self): 
     print('TestValueFunctions.setUp') 
     super(test_framework.ComplexTest, self).tearDown() 
     self.value = 4711 

    def tearDown(self): 
     print('TestValueFunctions.tearDown') 
     super(test_framework.ComplexTest, self).tearDown() 

    def test_value(self): 
     print('TestValueFunctions.test_value') 
     self.assertEqual(self.value, 4711) 

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

3) khi bây giờ cố gắng chạy này, tôi thấy chồng sau

TestValueFunctions.__init__ 
BasicTest.__init__ 
Traceback (most recent call last): 
    File "D:\MyDev\ljs_app\trunk\examples\python\unittest\test.py", line 23, in <module> 
    unittest.main() 
    File "C:\Python27\lib\unittest\main.py", line 94, in __init__ 
    self.parseArgs(argv) 
    File "C:\Python27\lib\unittest\main.py", line 149, in parseArgs 
    self.createTests() 
    File "C:\Python27\lib\unittest\main.py", line 155, in createTests 
    self.test = self.testLoader.loadTestsFromModule(self.module) 
    File "C:\Python27\lib\unittest\loader.py", line 65, in loadTestsFromModule 
    tests.append(self.loadTestsFromTestCase(obj)) 
    File "C:\Python27\lib\unittest\loader.py", line 56, in loadTestsFromTestCase 
    loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames)) 
    File "D:\MyDev\ljs_app\trunk\examples\python\unittest\test.py", line 7, in __init__ 
    super(test_framework.ComplexTest, self).__init__(*args, **kwargs) 
    File "D:\MyDev\ljs_app\trunk\examples\python\unittest\test_framework.py", line 6, in __init__ 
    super(unittest.TestCase, self).__init__(*args, **kwargs) 
TypeError: object.__init__() takes no parameters 
+0

Một trong những lợi thế lớn của 'super' là bạn ** không ** phải nêu rõ lớp cha. Như bạn thấy trong các lỗi bạn đang gọi 'đối tượng .__ init__' thay vì' TestCase .__ init__' với mã đó. – Bakuriu

+1

Chỉ trong Python 3 bạn có thể bỏ qua đối số lớp thành 'super'. – chepner

Trả lời

17

Thực tế phương pháp init của bạn là sai.

class BasicTest(unittest.TestCase): 
    def __init__(self, *args, **kwargs): 
     print('BasicTest.__init__') 
     super(unittest.TestCase, self).__init__(*args, **kwargs) 

nên là:

class BasicTest(unittest.TestCase): 
    def __init__(self, *args, **kwargs): 
     print('BasicTest.__init__') 
     super(BasicTest, self).__init__(*args, **kwargs) 

này sẽ gọi __init__ trên lớp mẹ của BasicTest, đó là TestCase. Điều này tương tự đối với thiết lập và tearDown:

class BasicTest(unittest.TestCase): 
    ... 
    def setUp(self): 
     print('BasicTest.setUp') 
     super(BasicTest, self).setUp() 
+0

Tuyệt vời: Tôi dường như đã hiểu lầm siêu nhưng bây giờ nó hoạt động như một say mê. Cảm ơn bạn! – doberkofler

+0

dòng cuối cùng của ví dụ thiết lập phải là: 'super (BasicTest, self) .setUp()'. Ngay bây giờ nó sẽ gọi tearDown cha mẹ phương pháp, mà không phải là logic.Điều tương tự đối với các mẫu mã câu hỏi. – manelvf

0

Ah super! Ai biết tại sao nó làm bất cứ điều gì. Nếu bạn ngừng sử dụng nó trong thử nghiệm của bạn và thay vào đó gọi một cách rõ ràng các lớp cha mẹ mà bạn muốn, như thế này:

class BasicTest(unittest.TestCase): 
    def __init__(self, *args, **kwargs): 
     print('BasicTest.__init__') 
     unittest.TestCase.__init__(self, *args, **kwargs) 

Bạn sẽ kết thúc với kết quả dưới đây:

TestValueFunctions.__init__ 
ComplexTest.__init__ 
TestValueFunctions.setUp 
ComplexTest.setUp 
TestValueFunctions.test_value 
TestValueFunctions.tearDown 
ComplexTest.tearDown 
. 
---------------------------------------------------------------------- 
Ran 1 test in 0.000s 

OK 

Xem: Python's Super is nifty, but you can't use it

+0

Điều đó chỉ đúng nếu bạn không mong đợi nó là một phần của nhiều thừa kế; nếu không, điều này sẽ phá vỡ mọi thứ và có khả năng gây ra hành vi bất ngờ. –

+0

Nó không phá vỡ mọi thứ. Đặc biệt vì 'unittest.TestCase' không sử dụng siêu. Đó là một trường hợp rõ ràng gọi mã bạn muốn theo thứ tự mà bạn muốn gọi nó. – aychedee

+0

Không đúng, nếu bạn có lớp này và lớp khác phân lớp 'unittest.TestCase' là cha mẹ trực tiếp cho lớp này, hoặc cách khác để kết thúc sớm hơn trong mro so với phương thức khác, nó sẽ có vấn đề. Có lẽ ít hơn trong trường hợp này, nhưng nói chung nó không phải là một lựa chọn tốt (đặc biệt nếu nó là một phân lớp trực tiếp của đối tượng) –

Các vấn đề liên quan