2012-03-22 27 views
10

Đây là sự cố xảy ra khi thực hiện một thử nghiệm duy nhất có nhiều chế độ lỗi độc lập do có nhiều luồng đầu ra. Tôi cũng muốn hiển thị các kết quả của việc xác nhận dữ liệu trên tất cả các chế độ đó, bất kể những gì không thành công trước. Tính không nhất quán của Python không có tính năng nào ngoài việc sử dụng một Suite để thể hiện một phép thử duy nhất, điều không thể chấp nhận được vì thử nghiệm đơn của tôi luôn cần phải chạy như một đơn vị duy nhất; nó không nắm bắt được bản chất của sự vật.Làm cách nào để xử lý nhiều xác nhận trong một Python đơn lẻ?

Ví dụ thực tế là thử nghiệm đối tượng cũng tạo nhật ký. Bạn muốn khẳng định đầu ra của các phương thức của nó, nhưng bạn cũng muốn khẳng định đầu ra bản ghi. Hai kết quả đầu ra yêu cầu các phép thử khác nhau, có thể được biểu diễn gọn gàng khi hai trong số các chứng khoán khẳng định các biểu thức, nhưng bạn cũng không muốn thất bại của một để ẩn sự thất bại có thể của bên kia trong thử nghiệm. Vì vậy, bạn thực sự cần phải kiểm tra cả hai cùng một lúc.

Tôi đã trộn lẫn với nhau tiện ích nhỏ hữu ích này để giải quyết vấn đề của tôi.

def logFailures(fnList): 
    failurelog = [] 
    for fn in fnList: 
     try: 
      fn() 
     except AssertionError as e: 
      failurelog.append("\nFailure %d: %s" % (len(failurelog)+1,str(e))) 

    if len(failurelog) != 0: 
     raise AssertionError(
      "%d failures within test.\n %s" % (len(failurelog),"\n".join(failurelog)) 
     ) 

nào được sử dụng như sau:

def test__myTest(): 
    # do some work here 
    logFailures([ 
     lambda: assert_(False,"This test failed."), 
     lambda: assert_(False,"This test also failed."), 
    ]) 

Kết quả là logFailures() sẽ nâng cao một ngoại lệ có chứa một bản ghi của tất cả các khẳng định đã được nêu ra trong các phương pháp trong danh sách.

Câu hỏi: Trong khi thực hiện công việc này, tôi tự hỏi liệu có cách nào tốt hơn để xử lý việc này, ngoài việc phải tạo ra các dãy kiểm tra lồng nhau và vv?

+3

"bạn cũng không muốn thất bại của một để ẩn sự cố có thể của người khác trong thử nghiệm". Nếu bạn muốn thử nghiệm hai thứ khác nhau, hãy thử hai bài kiểm tra khác nhau! –

+1

"bạn cũng không muốn thất bại của một để ẩn sự thất bại có thể của người khác trong thử nghiệm". Có - Tôi muốn: đây là những bài kiểm tra đơn vị. Nếu một thử nghiệm thất bại, sửa lỗi và chạy lại các thử nghiệm. –

Trả lời

12

Tôi không đồng ý với ý kiến ​​thống trị rằng người ta nên viết một phương pháp thử cho mỗi xác nhận. Có những tình huống mà bạn muốn kiểm tra nhiều thứ trong một phương pháp thử nghiệm. Dưới đây là câu trả lời của tôi cho làm thế nào để làm điều đó:

# Works with unittest in Python 2.7 
class ExpectingTestCase(unittest.TestCase): 
    def run(self, result=None): 
     self._result = result 
     self._num_expectations = 0 
     super(ExpectingTestCase, self).run(result) 

    def _fail(self, failure): 
     try: 
      raise failure 
     except failure.__class__: 
      self._result.addFailure(self, sys.exc_info()) 

    def expect_true(self, a, msg): 
     if not a: 
      self._fail(self.failureException(msg)) 
     self._num_expectations += 1 

    def expect_equal(self, a, b, msg=''): 
     if a != b: 
      msg = '({}) Expected {} to equal {}. '.format(self._num_expectations, a, b) + msg 
      self._fail(self.failureException(msg)) 
     self._num_expectations += 1 

Và đây là một số tình huống mà tôi nghĩ rằng nó rất hữu ích và không nguy hiểm:

1) Khi bạn muốn kiểm tra mã cho bộ dữ liệu khác nhau. Ở đây chúng ta có một hàm add() và tôi muốn thử nghiệm nó với một vài ví dụ đầu vào. Để viết 3 phương pháp thử nghiệm cho 3 tập dữ liệu có nghĩa là lặp lại chính mình mà là xấu. Đặc biệt nếu cuộc gọi phức tạp hơn:

class MyTest(ExpectingTestCase): 
    def test_multiple_inputs(self): 
     for a, b, expect in ([1,1,2], [0,0,0], [2,2,4]): 
      self.expect_equal(expect, add(a,b), 'inputs: {} {}'.format(a,b)) 

2) Khi bạn muốn kiểm tra nhiều đầu ra của một hàm. Tôi muốn kiểm tra mỗi đầu ra nhưng tôi không muốn một sự thất bại đầu tiên để mặt nạ ra hai khác.

class MyTest(ExpectingTestCase): 
    def test_things_with_no_side_effects(self): 
     a, b, c = myfunc() 
     self.expect_equal('first value', a) 
     self.expect_equal('second value', b) 
     self.expect_equal('third value', c) 

3) Kiểm tra những thứ có chi phí thiết lập cao. Các xét nghiệm phải chạy nhanh hoặc mọi người ngừng sử dụng chúng. Một số thử nghiệm yêu cầu kết nối mạng hoặc kết nối mạng mất một giây để thực sự làm chậm quá trình kiểm tra của bạn. Nếu bạn đang thử nghiệm bản thân kết nối db, thì bạn có thể cần phải thực hiện tốc độ nhấn. Nhưng nếu bạn đang thử nghiệm một cái gì đó không liên quan, chúng tôi muốn làm các thiết lập chậm một lần cho một bộ toàn bộ kiểm tra.

+1

Một cái gì đó như thế này nên có mặt trong các khung kiểm tra đơn vị theo mặc định. Có ai biết ai có chức năng này không? – pmos

10

Điều này có vẻ như quá kỹ thuật đối với tôi. Hoặc:

  • Sử dụng hai xác nhận trong một trường hợp thử nghiệm. Nếu khẳng định đầu tiên thất bại, đó là sự thật, bạn sẽ không biết liệu xác nhận thứ hai có được thông qua hay không. Tuy nhiên, bạn sẽ sửa mã, vì vậy hãy sửa nó, và sau đó bạn sẽ tìm hiểu xem câu lệnh thứ hai có được thông qua hay không.

  • Viết hai bài kiểm tra, một để kiểm tra từng điều kiện. Nếu bạn sợ mã trùng lặp trong các thử nghiệm, hãy đặt số lượng lớn mã trong phương thức trợ giúp mà bạn gọi từ các thử nghiệm.

3

Với việc sử dụng một thi này, thực hiện sẽ không dừng lại sau thất bại đầu tiên https://docs.python.org/3/library/unittest.html#subtests

Dưới đây là ví dụ với hai thất bại khẳng định:

class TestMultipleAsserts(unittest.TestCase): 

    def test_multipleasserts(self): 
     with self.subTest(): 
      self.assertEqual(1, 0) 
     with self.subTest(): 
      self.assertEqual(2, 0) 

Output sẽ là:

====================================================================== 
FAIL: test_multipleasserts (__main__.TestMultipleAsserts) (<subtest>) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "./test.py", line 9, in test_multipleasserts 
    self.assertEqual(1, 0) 
AssertionError: 1 != 0 

====================================================================== 
FAIL: test_multipleasserts (__main__.TestMultipleAsserts) (<subtest>) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "./test.py", line 11, in test_multipleasserts 
    self.assertEqual(2, 0) 
AssertionError: 2 != 0 

---------------------------------------------------------------------- 
Ran 1 test in 0.000s 

FAILED (failures=2) 

Bạn có thể dễ dàng bọc phụ đề như sau

class MyTestCase(unittest.TestCase): 
    def expectEqual(self, first, second, msg=None): 
     with self.subTest(): 
      self.assertEqual(first, second, msg) 

class TestMA(MyTestCase): 
    def test_ma(self): 
     self.expectEqual(3, 0) 
     self.expectEqual(4, 0) 
Các vấn đề liên quan