2013-01-22 28 views
5

Tôi đang xử lý một chuỗi các đối tượng do người dùng xác định. Nó trông tương tự như sau:Làm cách nào để xác nhận cuộc gọi chấp nhận đối số chuỗi bằng Python Mock?

class Thing(object): 
    def __init__(self, x, y): 
     self.x = x 
     self.y = y 

Phương pháp Tôi hiện đang thử nghiệm có chức năng tương tự như sau:

def my_function(things): 
    x_calc = calculate_something(t.x for t in things) 
    y_calc = calculate_something(t.y for t in things) 
    return x_calc/y_calc 

Vấn đề tôi đang phải đối mặt đang thử nghiệm các cuộc gọi đến calculate_something. Tôi muốn khẳng định rằng những cuộc gọi đã xảy ra, một cái gì đó giống như vậy:

calculateSomethingMock.assert_any_call(the_sequence) 

Tôi không quan tâm đến thứ tự của chuỗi truyền vào calculate_something, nhưng tôi quan tâm rằng các yếu tố đều đầy đủ. Tôi có thể bọc chức năng máy phát điện trong một cuộc gọi đến set, nhưng tôi không cảm thấy như thử nghiệm của tôi nên được quyết định loại trình tự được chuyển vào calculate_something. Tôi sẽ có thể vượt qua bất kỳ loại trình tự nào. Tôi có thể cách khác tạo ra một phương thức tạo chuỗi thay vì sử dụng cú pháp máy phát và giả lập phương thức đó, nhưng điều đó có vẻ như quá mức cần thiết.

Làm cách nào để cấu trúc tốt nhất xác nhận này hoặc thử nghiệm sự cố của tôi ở đây là dấu hiệu của mã có cấu trúc kém?

Tôi đang sử dụng Python 2.7.3 với Mock 1.0.1.

(Đối với bất cứ ai cảm thấy bắt buộc để bình luận về nó, tôi biết tôi đang làm bài kiểm tra cuối cùng và rằng điều này không được coi là thực tiễn nhất.)

Edit:

Sau khi đồng hồ this marvelous talk entitled "Why You Don't Get Mock Objects by Gregory Moeck" , Tôi đã xem xét lại liệu tôi có nên chế nhạo phương thức calculate_something hay không.

Trả lời

2

Tôi chưa chạm vào mã tôi đã làm việc trong một thời gian dài, nhưng tôi đã xem xét lại cách tiếp cận của mình để thử nghiệm nói chung.Tôi đã cố gắng cẩn thận hơn về những gì tôi làm và không chế giễu. Gần đây tôi đã nhận ra rằng tôi đã vô tình bắt đầu tuân thủ quy tắc này: giả lập điều gì đó nếu nó làm cho bài kiểm tra của tôi ngắn hơn và đơn giản hơn và để nó một mình nếu nó làm cho bài kiểm tra phức tạp hơn. Thử nghiệm đầu vào/đầu ra đơn giản đủ trong trường hợp của phương pháp này. Không có phụ thuộc bên ngoài như cơ sở dữ liệu hoặc tệp. Vì vậy, trong ngắn hạn, tôi nghĩ rằng câu trả lời cho câu hỏi của tôi là, "Tôi không nên giả calculate_something." Làm như vậy làm cho bài kiểm tra của tôi khó đọc và duy trì.

7

Nhìn vào tài liệu Mock, có call_args_list sẽ thực hiện những gì bạn muốn.

Vì vậy, bạn sẽ bỏ ra calculate_something trong bài kiểm tra của mình.

calculate_something = Mock(return_value=None) 

Sau khi bạn my_function đã hoàn tất, bạn có thể kiểm tra các đối số được truyền bằng cách thực hiện:

calculate_something.call_args_list 

mà sẽ trả về một danh sách của tất cả các cuộc gọi đến nó (với các yếu tố tương ứng thông qua).

Sửa:

(Xin lỗi nó đã cho tôi quá lâu, tôi đã phải cài đặt Python3.3 trên máy tính của tôi)

mymodule.py

class Thing: 
    ... 
def calculate_something: 
    ... 

def my_function(things): 
    # Create the list outside in order to avoid a generator object 
    # from being passed to the Mock object. 

    xs = [t.x for t in things] 
    x_calc = calculate_something(xs) 

    ys = [t.y for t in things] 
    y_calc = calculate_something(ys) 
    return True 

test_file. py

import unittest 
from unittest.mock import patch, call 
import mymodule 



class TestFoo(unittest.TestCase): 

    # You can patch calculate_something here or 
    # do so inside the test body with 
    # mymodule.calcualte_something = Mock() 
    @patch('mymodule.calculate_something') 
    def test_mock(self, mock_calculate): 

     things = [mymodule.Thing(3, 4), mymodule.Thing(7, 8)] 

     mymodule.my_function(things) 

     # call_args_list returns [call([3, 7]), call([4, 8])] 
     callresult = mock_calculate.call_args_list 


     # Create our own call() objects to compare against 
     xargs = call([3, 7]) 
     yargs = call([4, 8]) 

     self.assertEqual(callresult, [xargs, yargs]) 

     # or 
     # we can extract the call() info 
     # http://www.voidspace.org.uk/python/mock/helpers.html#mock.call.call_list 
     xargs, _ = callresult[0] 
     yargs, _ = callresult[1] 

     xexpected = [3, 7] 
     yexpected = [4, 8] 

     self.assertEqual(xargs[0], xexpected) 
     self.assertEqual(yargs[0], yexpected) 

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

Tôi cố gắng tránh đào sâu vào danh sách đó, nhưng tôi cho rằng đó có thể là cách duy nhất. Bạn có thể cung cấp một ví dụ? – jpmc26

+0

Cảm ơn. Thử nghiệm này dựa vào thứ tự bảo quản phương thức và nó cũng dựa vào phương thức truyền trong danh sách. Tôi không phải là rất quan tâm đến các thử nghiệm dựa trên thứ tự. Nếu tôi quyết định thay đổi một số cấu trúc dữ liệu khác cho đối số được chuyển thành 'calculate_something', tôi có muốn thử nghiệm thất bại không? Hoặc ngược lại, nếu tôi thay đổi bài kiểm tra để kiểm tra cuộc gọi cho một kiểu dữ liệu khác, tôi có muốn sửa đổi phương thức để làm lại nó không? – jpmc26

+0

Có, nhưng hãy nhớ đây là một ví dụ. Bạn có thể chuyển 'calculate_something' bất kỳ cấu trúc dữ liệu nào khác, chỉ cần cập nhật thử nghiệm để phản ánh điều đó (Bằng cách thay đổi giá trị mong đợi). Bạn muốn thử nghiệm để vượt qua sau khi tất cả. Bạn đã thấy cách chuyển đối số sang 'calculate_something' bằng' call_args_list'. Sau đó, đó chỉ là vấn đề so sánh dữ liệu có cấu trúc với những gì bạn đang mong đợi. –

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