Chế nhạo một hàm để nâng một Ngoại lệ để kiểm tra một khối ngoại trừ


118

Tôi có một hàm ( foo) gọi một hàm khác ( bar). Nếu việc gọi bar()tăng lên một HttpError, tôi muốn xử lý đặc biệt nếu mã trạng thái là 404, nếu không thì tăng lại.

Tôi đang cố gắng viết một số bài kiểm tra đơn vị xung quanh foochức năng này , chế nhạo cuộc gọi tới bar(). Thật không may, tôi không thể nhận được cuộc gọi bị chế nhạo bar()để nêu ra một Ngoại lệ bị chặn bởi exceptkhối của tôi .

Đây là mã của tôi minh họa vấn đề của tôi:

import unittest
import mock
from apiclient.errors import HttpError


class FooTests(unittest.TestCase):
    @mock.patch('my_tests.bar')
    def test_foo_shouldReturnResultOfBar_whenBarSucceeds(self, barMock):
        barMock.return_value = True
        result = foo()
        self.assertTrue(result)  # passes

    @mock.patch('my_tests.bar')
    def test_foo_shouldReturnNone_whenBarRaiseHttpError404(self, barMock):
        barMock.side_effect = HttpError(mock.Mock(return_value={'status': 404}), 'not found')
        result = foo()
        self.assertIsNone(result)  # fails, test raises HttpError

    @mock.patch('my_tests.bar')
    def test_foo_shouldRaiseHttpError_whenBarRaiseHttpErrorNot404(self, barMock):
        barMock.side_effect = HttpError(mock.Mock(return_value={'status': 500}), 'error')
        with self.assertRaises(HttpError):  # passes
            foo()

def foo():
    try:
        result = bar()
        return result
    except HttpError as error:
        if error.resp.status == 404:
            print '404 - %s' % error.message
            return None
        raise

def bar():
    raise NotImplementedError()

Tôi đã làm theo các tài liệu Mock nói rằng bạn nên đặt phiên bản side_effectcủa một lớp Mockthành một Exceptionlớp để hàm bị chế nhạo có thể phát sinh lỗi.

Tôi cũng đã xem xét một số Q & As có liên quan khác của StackOverflow, và có vẻ như tôi đang làm điều tương tự mà họ đang làm để gây ra và Ngoại lệ được nêu ra bởi chế độ của họ.

Tại sao việc đặt giá side_effecttrị barMockkhông làm tăng dự kiến Exception? Nếu tôi đang làm điều gì đó kỳ lạ, tôi nên kiểm tra logic trong exceptkhối của mình như thế nào?


Tôi khá chắc chắn rằng ngoại lệ của bạn đang được nêu ra, nhưng tôi không chắc bạn đang đặt resp.statusmã ở đó như thế nào . Từ đâu HTTPErrorđến?
Martijn Pieters

@MartijnPieters HttpErrorlà một lớp được định nghĩa trong lib của Googleapiclient mà chúng tôi sử dụng trong GAE. Nó __init__được xác định với các tham số, (resp, content)vì vậy tôi đã cố gắng tạo một phiên bản giả cho phản hồi, với mã trạng thái thích hợp được chỉ định.
Jesse Webb

Đúng, vì vậy nó là lớp này ; nhưng bạn không cần phải sử dụng return_valuesau đó; respkhông được gọi .
Martijn Pieters

1
Tôi đã thử lại mã của mình mà không sử dụng HttpErrorvà thay vào đó chỉ thử sử dụng một phiên bản thông thường Exception. Điều này hoạt động hoàn hảo. Điều này có nghĩa là nó phải HttpErrorliên quan đến cách tôi định cấu hình phiên bản, có thể liên quan đến cách tôi tạo một Mockphiên bản cho phản hồi.
Jesse Webb

Câu trả lời:


141

Mô hình của bạn đang nâng cao ngoại lệ tốt, nhưng error.resp.statusgiá trị bị thiếu. Thay vì sử dụng return_value, chỉ cần nói Mockrằng đó statuslà một thuộc tính:

barMock.side_effect = HttpError(mock.Mock(status=404), 'not found')

Các đối số từ khóa bổ sung Mock()được đặt làm thuộc tính trên đối tượng kết quả.

Tôi đặt định nghĩa foovà của bạn bartrong một my_testsmô-đun, được thêm vào trong HttpErrorlớp để tôi cũng có thể sử dụng nó và sau đó bài kiểm tra của bạn có thể chạy thành công:

>>> from my_tests import foo, HttpError
>>> import mock
>>> with mock.patch('my_tests.bar') as barMock:
...     barMock.side_effect = HttpError(mock.Mock(status=404), 'not found')
...     result = my_test.foo()
... 
404 - 
>>> result is None
True

Bạn thậm chí có thể thấy print '404 - %s' % error.messagedòng chạy, nhưng tôi nghĩ bạn muốn sử dụng error.contentở đó thay thế; đó là các HttpError()tập thuộc tính từ đối số thứ hai, ở bất kỳ tỷ lệ nào.


2
những side_effectlà phần quan trọng
Daniel Butler
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.