单元测试时,Python类方法没有被正确模拟

时间:2015-09-18 07:39:31

标签: python unit-testing mocking

我使用flask_restful创建了一个API。名为TotalUserResponse的资源或API类有一个名为process_get_request的方法,我正在尝试进行单元测试。

def process_get_request(self):
    params = parser_get.parse_args()
    user_id = params.get('user_id')
    if not user_id:
        raise ValueError("User id is empty")

    user = session.query(User).get(user_id)
    if not user:
        raise MyValidationError("User not found")

    # total applied, favourited and archived
    aggregated_actions = self.get_aggregated_actions(user_id)
    response = dict(applied=aggregated_actions[0],
                    favourited=aggregated_actions[1],
                    archived=aggregated_actions[2])

    return response

unittest -

@mock.patch('application.resources.user_response.TotalUserResponse', autospec=True)
@mock.patch('application.models.session.query', autospec=True)
@mock.patch('flask_restful.reqparse.RequestParser.parse_args', autospec=True)
def test_process_get_request(self, parse_args_mock, query_mock, total_user_response_mock):

    parse_args_mock.return_value = dict(user_id='xxxxxx')
    query_mock.return_value.get.return_value = 'something non empty'
    expected_applied, expected_favourited, expected_archived = 5, 10, 20
    total_user_response_mock.return_value.get_aggregated_actions.return_value = (expected_applied, expected_favourited, expected_archived)

    expected_response = dict(applied=expected_applied,
                             favourited=expected_favourited, archived=expected_archived)

    self.assertEqual(self.total_user_response.process_get_request(), expected_response)

我的单位测试失败了 -

AssertionError: {'applied': <MagicMock name='query().filter().first().__getitem__()' id='1543892 [truncated]... != {'applied': 5, 'archived': 20, 'favourited': 10}

从上面的错误消息中,我了解 get_aggregated_user_actions 未被嘲笑。当我调试它时,我看到调试器将我带入函数中,如果它被正确模拟,它将不会发生。

怎么了?请帮帮我。

1 个答案:

答案 0 :(得分:1)

在您的测试中,您使用的是self.total_user_response.process_get_request():您致电process_get_request()这是self.total_user_response的方法,而不是您以前嘲笑的方法。恕我直言,修补静态引用而不是对象引用更好,更简单。修补对象使测试更复杂,更难理解/维护,将其作为最后一个资源使用。

要减少这类问题,最好重写一下你的测试:

@mock.patch('application.resources.user_response.TotalUserResponse.get_aggregated_actions', autospec=True)
@mock.patch('application.models.session.query.get', return_value='something non empty', autospec=True)
@mock.patch('flask_restful.reqparse.RequestParser.parse_args', autospec=True, return_value=dict(user_id='xxxxxx'))
def test_process_get_request(self, parse_args_mock, get_mock, get_aggregated_mock):
    expected_applied, expected_favourited, expected_archived = 5, 10, 20
    get_aggregated_mock.return_value = (expected_applied, expected_favourited, expected_archived)

    expected_response = dict(applied=expected_applied,
                             favourited=expected_favourited, archived=expected_archived)

    self.assertEqual(self.total_user_response.process_get_request(), expected_response)

也许它包含一些错误,但我希望这个想法很明确:

  • 以最精确的方式模拟你真正需要的东西。
  • 将与测试中真正无关的所有数据放入测试方法中。