2013-04-11 23 views
15

Tôi là người python. Vào những ngày này tôi đang lái xe bản thân mình để làm một bài kiểm tra đơn vị hoàn chỉnh hơn về một số module cốt lõi trong dự án của tôi. Vì chúng ta luôn thử nghiệm đơn vị với các phương thức 'assertEqual', 'assertTrue' và cứ thế, tất cả các phương thức này đều yêu cầu một giá trị trả về từ hàm đang được thử nghiệm. Tôi tự hỏi làm thế nào để thực hiện kiểm tra đơn vị đơn giản trên một số hàm không có giá trị trả về .Trong python, làm thế nào để làm bài kiểm tra đơn vị trên một hàm không có giá trị trả về?

Tôi muốn hiển thị một ví dụ nhỏ ở đây, cách kiểm tra hàm def foo (tự, msg) trong HelloTest?

class HelloTest(object): 
    def foo(self, msg): 
     MSG = msg.upper() 
     self.bar(MSG) 

    def bar(self, MSG): 
     print MSG 

Trả lời

5

Trong trường hợp cụ thể này, tôi sẽ thử in, sau đó sử dụng mô phỏng trong xác nhận của tôi.

Trong Python, bạn sẽ sử dụng Mock package để thử.

+0

+1: Đối với con trỏ tới 'mock'. –

+2

Vâng, nếu anh ta đang sử dụng bất cứ điều gì bên dưới Python 3 thì nó không phải là đơn giản để in thử. Anh ta có thể thử sys.stdout, nhưng anh ta phải thay đổi thanh – aychedee

2

Trong Python 3, bạn có thể tell print where to print to:

in (* đối tượng, tháng chín ='', kết thúc = '\ n', file = sys.stdout, tuôn ra = False)

vì vậy, thêm một đối số tùy chọn:

def bar(self, MSG, file=sys.stdout): 
    print(MSG, file=file) 

Trong sử dụng bình thường, nó sẽ in ra stdout, nhưng đối với các bài kiểm tra đơn vị bạn có thể vượt qua tập tin của riêng bạn.

Trong Python 2 đó là một hỗn độn chút, nhưng bạn có thể redirect stdout to a StringIO buffer:

import StringIO 
import sys 

out = StringIO.StringIO() 
sys.stdout = out 

# run unit tests 

sys.stdout = sys.__stdout__ 

# check the contents of `out` 
+1

Giải pháp tốt để làm bài kiểm tra đơn vị về chức năng với đầu ra. Nhưng những gì tôi quan tâm nhất là làm thế nào để kiểm tra 'def foo (self, msg)', vì không phải tất cả các chức năng đều làm điều gì đó với stdout – Yarkee

2

mã của bạn có thể được như đưa ra dưới đây mà làm cùng nhiệm vụ như trên:

class HelloTest(object): 

    def foo(self, msg): 
     self.msg = msg.upper() 
     self.bar() 

    def bar(self): 
     print self.msg 

Đơn vị kiểm tra là:

from hello import HelloTest 
import unittest 

class TestFoo(unittest.TestCase): 
    def test_foo_case(self): 
     msg = "test" 
     ob = HelloTest() 
     ob.foo(msg) 
     expected = "TEST" 
     self.assertEqual(ob.msg, expected) 

if __name__ == '__main__': 
    unittest.main(exit=False) 
9

Như một câu trả lời khác được đề cập, bạn có thể sử dụng thư viện giả Python để đưa ra các xác nhận về các cuộc gọi đến các hàm/phương thức

from mock import patch 
from my_module import HelloTest 
import unittest 

class TestFoo(unittest.TestCase): 

    @patch('hello.HelloTest.bar') 
    def test_foo_case(self, mock_bar): 

     ht = HelloTest() 

     ht.foo("some string") 
     self.assertEqual(ob.msg, "SOME STRING") 
     self.assertTrue(mock_bar.called) 

Phương thức này sẽ loại bỏ phương thức bar trên HelloTest và thay thế bằng đối tượng giả ghi lại cuộc gọi.

Chế nhạo là một chút lỗ thỏ. Chỉ làm điều đó khi bạn hoàn toàn phải làm vì nó làm cho các bài kiểm tra của bạn trở nên giòn. Bạn sẽ không bao giờ nhận thấy một sự thay đổi API cho một đối tượng giả lập ví dụ.

2

Nhờ giới thiệu @Jordan 's, tôi mã này và nghĩ rằng đó là một thử nghiệm đơn vị hoàn toàn khả thi cho HelloTest.foo

from mock import Mock 
import unittest 


class HelloTestTestCase(unittest.TestCase): 
    def setUp(self): 
     self.hello_test = HelloTest() 

    def tearDown(self): 
     pass 

    def test_foo(self): 
     msg = 'hello' 
     expected_bar_arg = 'HELLO' 
     self.hello_test.bar = Mock() 

     self.hello_test.foo(msg) 
     self.hello_test.bar.assert_called_once_with(expected_bar_arg) 


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

Tôi hoàn toàn không hiểu tại sao mọi người đều muốn kiểm tra foo mà các cuộc gọi thanh.

Foo có một số chức năng và chức năng này cần được kiểm tra. Nếu foo đang sử dụng thanh để làm điều này không phải là mối quan tâm của tôi.

Kết quả mong muốn là sau khi foo(msg) được gọi, là msg.upper() được gửi tới chế độ chờ.

Bạn có thể redirect stdout to a string buffer và kiểm tra xem nội dung của bộ đệm chuỗi này có khớp với những gì bạn mong đợi hay không.

Ví dụ:

import sys 
import unittest 
from io import TextIOWrapper, BytesIO 

class TestScript(unittest.TestCase): 
    def setUp(self): 
     self._old_stdout = sys.stdout 
     sys.stdout = TextIOWrapper(BytesIO(), sys.stdout.encoding) 

    def _output(self): 
     self._stdout.seek(0) 
     return self._stdout.read() 

    def test_foo(self): 
     hello_test = HelloTest() 
     hello_test.foo("blub") 
     self.assertEqual(self._output(), "BLUB") 

    def tearDown(self): 
     sys.stdout = self._old_stdout 
     self._stdout.close() 

Bạn cũng có thể làm điều đó cho stdin (và ghi vào stdin để thử một số đầu vào) và bạn có thể phân lớp TestIOWrapper nếu bạn cần bất cứ điều gì đặc biệt để được thực hiện, như cho phép văn bản không phải unicode được gửi đến sys.stdout mà không cần sử dụng sys.stdout.buffer (Python 2 so với Python 3). Có một ví dụ về điều đó trong this SO answer. Khi bạn (vẫn) chỉ sử dụng Python 2, sau đó sử dụng StringIO có thể tốt hơn sử dụng mô-đun io.

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