2010-08-31 28 views
9

Tôi có một nhóm các trường hợp thử nghiệm mà tất cả phải có chính xác cùng một thử nghiệm được thực hiện, dọc theo dòng "Có phương pháp x trả về tên của một tệp hiện có?"Làm cách nào để thêm phương pháp thử nghiệm vào một nhóm các lớp có nguồn gốc từ Django TestCase?

Tôi nghĩ rằng cách tốt nhất để làm điều đó sẽ là một lớp cơ sở bắt nguồn từ TestCase mà tất cả chúng đều chia sẻ và chỉ cần thêm bài kiểm tra vào lớp đó. Thật không may, khuôn khổ thử nghiệm vẫn cố gắng chạy thử nghiệm cho lớp cơ sở, nơi nó không có ý nghĩa.

class SharedTest(TestCase): 
    def x(self): 
     ...do test... 

class OneTestCase(SharedTest): 
    ...my tests are performed, and 'SharedTest.x()'... 

Tôi cố gắng để hack trong một kiểm tra đơn giản bỏ qua kiểm tra nếu nó được gọi là trên một đối tượng của lớp cơ sở chứ không phải là một lớp học có nguồn gốc như thế này:

class SharedTest(TestCase): 
     def x(self): 
      if type(self) != type(SharedTest()): 
       ...do test... 
      else: 
       pass 

nhưng đã nhận lỗi này:

ValueError: no such test method in <class 'tests.SharedTest'>: runTest 

Trước tiên, tôi muốn có bất kỳ đề xuất thanh lịch nào để thực hiện việc này. Thứ hai, mặc dù tôi không thực sự muốn sử dụng loại() hack, tôi muốn hiểu tại sao nó không hoạt động.

+0

@jivanamara: Có một cách để tránh phương pháp kiểm tra siêu lớp khỏi tính _and_ để viết phương thức thử mà không có kiểm tra 'if getattr (...)'. Xem bản cập nhật thứ hai cho câu trả lời của tôi. –

Trả lời

1

Tôi gặp phải sự cố tương tự. Tôi không thể ngăn chặn các phương pháp thử nghiệm trong lớp cơ sở đang được thực hiện nhưng tôi đảm bảo rằng nó đã không thực hiện bất kỳ mã thực tế. Tôi đã làm điều này bằng cách kiểm tra một thuộc tính và trở về ngay lập tức nếu nó được thiết lập. Thuộc tính này chỉ được thiết lập cho lớp cơ sở và do đó các thử nghiệm chạy ở mọi nơi khác nhưng lớp cơ sở.

class SharedTest(TestCase): 
    def setUp(self): 
     self.do_not_run = True 

    def test_foo(self): 
     if getattr(self, 'do_not_run', False): 
      return 
     # Rest of the test body. 

class OneTestCase(SharedTest): 
    def setUp(self): 
     super(OneTestCase, self).setUp() 
     self.do_not_run = False 

Đây là một chút đột phá. Có có thể là một cách tốt hơn để làm điều này nhưng tôi không chắc chắn cách .

Cập nhật

Như sdolan says một mixin là đúng cách. Tại sao tôi không thấy điều đó trước đây?

Cập nhật 2

(Sau khi đọc comments) Nó sẽ được tốt đẹp nếu (1) phương pháp lớp cha có thể tránh được hackish if getattr(self, 'do_not_run', False): kiểm tra; (2) nếu số lần kiểm tra được tính chính xác.

Có thể có cách để thực hiện việc này. Django chọn và thực hiện tất cả các lớp kiểm tra trong tests, có thể là tests.py hoặc gói có tên đó. Nếu siêu lớp thử nghiệm được khai báo bên ngoài mô-đun thử nghiệm thì điều này sẽ không xảy ra. Nó vẫn có thể được kế thừa bởi các lớp thử nghiệm. Ví dụ: SharedTest có thể được đặt trong app.utils và sau đó được sử dụng bởi các trường hợp thử nghiệm. Đây sẽ là một phiên bản sạch hơn của giải pháp trên.

# module app.utils.test 
class SharedTest(TestCase): 
    def test_foo(self): 
     # Rest of the test body. 

# module app.tests 
from app.utils import test 
class OneTestCase(test.SharedTest): 
    ... 
+0

Bởi vì bạn đã không hỏi về nó trên SO :) – sdolan

+0

Đây là những gì tôi mã hóa sau khi đặt câu hỏi. Đó là một chút của một hack, nhưng pylint thích nó tốt hơn và tôi không thấy rằng nó tồi tệ hơn đáng kể so với mixin. Mặt trái chỉ là nó thêm một thử nghiệm không tồn tại vào số kiểm tra ... không phải cái gì đó sẽ giữ cho tôi vào ban đêm. – JivanAmara

+0

Vì tôi không quen thuộc với triết lý mixin, tôi đã từ chối một người bạn và anh ấy đã xác nhận sự do dự của tôi; nói rằng mixin được cho là độc lập. Tôi sẽ đi với giải pháp này vì giải pháp mixin làm cho mixin phụ thuộc vào các lớp sẽ sử dụng nó. – JivanAmara

22

Bạn có thể sử dụng một mixin bằng cách tận dụng các Á hậu kiểm tra chỉ chạy thử nghiệm kế thừa từ unittest.TestCase Ví dụ (mà Django TestCase thừa hưởng từ.):

class SharedTestMixin(object): 
    # This class will not be executed by the test runner (it inherits from object, not unittest.TestCase. 
    # If it did, assertEquals would fail , as it is not a method that exists in `object` 
    def test_common(self): 
     self.assertEquals(1, 1) 


class TestOne(TestCase, SharedTestMixin): 
    def test_something(self): 
     pass 

    # test_common is also run 

class TestTwo(TestCase, SharedTestMixin): 
    def test_another_thing(self): 
     pass 

    # test_common is also run 

Để biết thêm thông tin về lý do tại sao công trình này thực hiện tìm kiếm thứ tự độ phân giải phương thức python và đa kế thừa.

+0

+1. Đây là cách sạch sẽ để đi về nó. –

+0

Cảm ơn câu trả lời của bạn, Tôi đã bắt đầu theo cách này và không thích rằng tôi có một lớp gọi là các phương thức mà nó không có. Pylint cũng sủa về điều này, và tôi sử dụng pylint nặng nề. – JivanAmara

+0

@jivanamara: Bạn không cần phải gọi 'test_common' trong các lớp kiểm tra' TestOne' và 'TestTwo' của bạn. Nó được "trộn lẫn" vì nó là một phần của lớp thông qua nhiều kế thừa. – sdolan

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