2012-09-21 15 views
16

Thư viện nháp tôi sử dụng là ... mock.Làm thế nào để giả lập các hàm lồng nhau?

Tôi đã xem xét vấn đề "hàm lồng nhau" này khi tôi cố gắng viết trường hợp thử nghiệm cho một hàm (mã kế thừa).

Hàm này sử dụng hàm lồng nhau rất phức tạp với phụ thuộc nhiều vào các mô-đun khác.

Tôi tự hỏi liệu có thể giả lập các hàm lồng nhau với mock hay không.

Trả lời

2

Bạn đang cố gắng thay thế hàm lồng nhau bằng đối tượng giả? Nếu vậy, điều đó khá đơn giản, cho dù chức năng phức tạp thế nào đi chăng nữa. Bạn có thể sử dụng MagicMock để thay thế khá nhiều đối tượng python bất kỳ.

Nếu bạn cần mô phỏng hàm trả về thứ gì đó, bạn chỉ có thể đặt tham số return_value của MagicMock. Nó sẽ giống như thế này:

>>> super_nested_mock = mock.MagicMock() 
>>> super_nested_mock.return_value = 42 
>>> super_nested_mock() 
42 

Tuy nhiên, nếu bạn đang cố gắng để kiểm tra một đoạn mã mà các cuộc gọi chức năng super_nested của bạn ở đâu đó bên trong, và muốn thử nó ra, bạn sẽ cần phải sử dụng một patch . Trong thư viện giả, nó sẽ giống như thế này:

with patch('super_nested') as super_nested_mock: 
    super_nested_mock.return_value = "A good value to test with" 
    assert my_function_that_calls_super_nested(5) == 20 

Ở đây, bất cứ điều gì trong khối with mà thông thường sẽ gọi super_nested thay vào đó sẽ gọi super_nested_mock và chỉ trả về giá trị mà bạn thiết lập để nó.

Có một số sự tinh tế đối với chính xác những gì bạn cần đặt trong cuộc gọi bản vá. Chủ yếu, bạn muốn vá các đối tượng như mô-đun bạn đang thử nghiệm sẽ nhìn thấy nó. Xem "where to patch" để biết thêm hướng dẫn.

+1

Điều này sẽ không hoạt động vì hàm lồng nhau chỉ tồn tại trong hàm tôi muốn kiểm tra. Vì vậy, 'patch' không thể định vị và thay thế nó trực tiếp. – satoru

+0

Tôi hiểu, tôi đoán tôi đã hiểu lầm chính xác bạn đang cố kiểm tra cái gì. Tôi sẽ để nó ở đây vì mục đích của hậu thế. Chúc may mắn. – Wilduck

2

Cách duy nhất tôi đã nhìn thấy điều này thực hiện là để tự động tạo ra một bản sao của chức năng bên ngoài của bạn, thay đổi hằng số đối tượng mã của chức năng với các mã cho chức năng chế giễu của bạn:

Does an equivalent of override exist for nested functions?

5

Một tùy chọn là thay đổi chức năng của bạn để nó tùy chọn chấp nhận chức năng để gọi ví dụ nếu bạn có:

def fn_to_test(): 
    def inner_fn(): 
    return 1 
    return inner_fn() + 3 

Thay đổi nó để:

def fn_to_test(inner_fn = null) 
    def inner_fn_orig(): 
    return 1 
    if inner_fn==null: 
    inner_fn = inner_fn_orig 
    return fn() + 3 

Sau đó, "thực" sử dụng sẽ nhận được các chức năng bên trong bên phải, và trong các thử nghiệm của bạn, bạn có thể cung cấp của riêng bạn.

fn_to_test() # calls the real inner function 
def my_inner_fn(): 
    return 3 
fn_to_test(inner_fn=my_inner_fn) # calls the new version 

Bạn cũng có thể làm điều này:

def fn_to_test(): 
    def inner_fn_orign(): 
    return 1 
    inner_fn = inner_fn_orig 
    try: 
    inner_fn = fn_to_test.inner_fn 
    excecpt AttributeError: 
    pass 
    return inner_fn() + 3 

Bằng cách này bạn chỉ cần định nghĩa override:

fn_to_test() # calls the real inner function 
def my_inner_fn(): 
    return 3 
fn_to_test.inner_fn = my_inner_fn 
fn_to_test() # calls the new version 
18

ví dụ bạn cần phải thử gọi hàm lồng nhau (chức năng xích) từ Google DRIVE API

result = get_drive_service().files().insert(body='body', convert=True).execute() 

, do đó bạn cần phải vá thông qua chức năng: service_mock(), tệp(), chèn(), cho đến khi cuối cùng thực hiện() trả lời:

from mock import patch 
with patch('path.to.import.get_drive_service') as service_mock: 
    service_mock.return_value.files.return_value.insert.\ 
    return_value.execute.return_value = {'key': 'value', 'status': 200} 

chương trình chính: đầu tiên. return_value .second. return_value .thứ ba. return_value .last. return_value = rsp

+2

Điều này đã lưu vào cuối tuần của tôi. Lưu ý rằng các thuộc tính lồng nhau không cần phải bị xích với 'return_value'. – Antwan