Câu hỏi Python mô phỏng nhiều giá trị trả về


Tôi đang sử dụng pythons mock.patch và muốn thay đổi giá trị trả lại cho mỗi cuộc gọi. Đây là báo trước: chức năng đang được vá không có đầu vào, vì vậy tôi không thể thay đổi giá trị trả về dựa trên đầu vào.

Đây là mã của tôi để tham khảo.

def get_boolean_response():
    response = io.prompt('y/n').lower()
    while response not in ('y', 'n', 'yes', 'no'):
        io.echo('Not a valid input. Try again'])
        response = io.prompt('y/n').lower()

    return response in ('y', 'yes')

Mã thử nghiệm của tôi:

@mock.patch('io')
def test_get_boolean_response(self, mock_io):
    #setup
    mock_io.prompt.return_value = ['x','y']
    result = operations.get_boolean_response()

    #test
    self.assertTrue(result)
    self.assertEqual(mock_io.prompt.call_count, 2)

io.prompt chỉ là một phiên bản độc lập của nền tảng (trăn 2 và 3) của "đầu vào". Vì vậy, cuối cùng tôi đang cố gắng để loại bỏ đầu vào của người dùng. Tôi đã thử sử dụng một danh sách cho giá trị trả lại, nhưng điều đó không có đường may để làm việc.

Bạn có thể thấy rằng nếu giá trị trả về là một cái gì đó không hợp lệ, tôi sẽ chỉ nhận được một vòng lặp vô hạn ở đây. Vì vậy, tôi cần một cách để cuối cùng thay đổi giá trị trả lại, để kiểm tra của tôi thực sự kết thúc.

(một cách khác để trả lời câu hỏi này có thể là giải thích cách tôi có thể bắt chước đầu vào của người dùng trong một bài kiểm tra đơn vị)


Không phải là lừa đảo câu hỏi này chủ yếu là vì tôi không có khả năng thay đổi đầu vào.

Một trong những ý kiến ​​của câu trả lời trên câu hỏi này nằm trên cùng một dòng, nhưng không có câu trả lời / nhận xét nào được cung cấp.


76
2017-07-22 20:25


gốc


response is not 'y' or 'n' or 'yes' or 'no' trong không phải làm những gì bạn nghĩ. Xem Làm cách nào để thử nghiệm một biến đối với nhiều giá trị? và bạn nên không phải sử dụng is để so sánh các giá trị chuỗi, sử dụng == để so sánh giá trị, không phải đối tượng nhận dạng. - Martijn Pieters♦
Ngoài ra hãy cẩn thận ở đây. Có vẻ như bạn đang cố gắng sử dụng is để so sánh các chuỗi ký tự. Đừng làm thế. Thực tế là nó hoạt động (đôi khi) chỉ là một chi tiết thực hiện trong CPython. Cũng thế, response is not 'y' or 'n' or 'yes' or 'no' có lẽ không làm những gì bạn nghĩ là ... - mgilson


Các câu trả lời:


Bạn có thể chỉ định có thể lặp lại đến side_effectvà mô hình sẽ trả về giá trị tiếp theo trong chuỗi mỗi khi được gọi:

>>> from unittest.mock import Mock
>>> m = Mock()
>>> m.side_effect = ['foo', 'bar', 'baz']
>>> m()
'foo'
>>> m()
'bar'
>>> m()
'baz'

Trích dẫn Mock() tài liệu:

Nếu side_effect là một iterable, sau đó mỗi cuộc gọi đến mô hình sẽ trả về giá trị tiếp theo từ iterable.

Như một sang một bên, thử nghiệm response is not 'y' or 'n' or 'yes' or 'no' sẽ không phải công việc; bạn đang hỏi liệu biểu thức (response is not 'y') là đúng, hoặc 'y' là đúng (luôn luôn như vậy, một chuỗi không trống luôn đúng), vv Các biểu thức khác nhau ở hai bên của or toán tử là độc lập. Xem Làm cách nào để thử nghiệm một biến đối với nhiều giá trị?

Bạn nên cũng thế không dùng is để kiểm tra đối với chuỗi. Trình thông dịch CPython có thể tái sử dụng các đối tượng chuỗi trong một số trường hợp nhất định, nhưng đây không phải là hành vi mà bạn nên dựa vào.

Như vậy, sử dụng:

response not in ('y', 'n', 'yes', 'no')

thay thế; điều này sẽ sử dụng bình đẳng kiểm tra (==) để xác định xem response tham chiếu một chuỗi có cùng nội dung (giá trị).

Ứng dụng tương tự response == 'y' or 'yes'; sử dụng response in ('y', 'yes') thay thế.


149
2017-07-22 20:34



Có cách nào để làm điều này với tiêu chuẩn mock? Có cách nào để sử dụng bản vá với MagicMock như tôi đang làm với mô hình tiêu chuẩn không? - Nick Humrich
@Humdinger: Đây là một tính năng của stardard Mock lớp học. - Martijn Pieters♦
@Humdinger: lưu ý rằng mock.patch() mặc định để sử dụng MagicMock, một phân lớp của Mock. - Martijn Pieters♦
Chỉ định một danh sách sẽ chỉ hoạt động với python 3. Thử nghiệm với python 2.7 Tôi cần sử dụng một iterator thay vào đó (m.side_effect = iter(['foo', 'bar', 'baz'])). - user686249
@ user686249: Tôi thực sự có thể tái tạo điều này, bởi vì việc xác định từ một phương thức tạo ra lambda (một hàm), không phải MagicMock. Một đối tượng hàm không thể có tài sản, vì vậy side_effect thuộc tính có để có thể lặp lại. Bạn không nên được speccing phương pháp như vậy mặc dù. Sử dụng tốt hơn mock.patch.object(requests.Session, 'post'); kết quả trong đối tượng bản vá tự động hóa thông số kỹ thuật đúng cách, và hỗ trợ side_effect đúng. - Martijn Pieters♦