首页 > 解决方案 > Python module pytest-mock how to test method call arguments when one class call another class instance?

问题描述

I started out learning unit testing using pytest a couple of days ago, and got interested in the pytest-mock plugin (https://github.com/pytest-dev/pytest-mock).

I have been able to write quite a lot of unit tests to test my code, but now I would like to test how parts of my code interact with other objects. Let's say that I have class B, which is the class that I am interested in testing, that have a method that will call a method in class A, and I would like to assert that the method call was made with the expected arguments when class B make the call to class A.

I put together some example hack (see the link below) that will get the job done, but as you can see this is probably not the proper way of doing things. So my question is, how is this properly handled by using the Python mock or pytest-mock modules? Answers not based on the pytest-mock plugin are appreciated as well.

In the code below it is the assert that I am not happy about, since I would prefer to use the existing pytest-mock "assert_called_once_with(...)"-method, but I just can't get it to work. All information is available in the mock-object, but I don't understand how to properly use the pytest-mock API in this case.

def test_how_class_b_interact_with_class_a(mocker):
    class A(object):
        def further_process_nbr(self, nbr):
            pass # don't care for the sake of this example

    class B(object):
        def __init__(self):
            self.a = A()

        def process_nbr(self, nbr):
            nbr += 2 # do something fancy with number and then have it further processed by object a
            return self.a.further_process_nbr(nbr)

    nbr = 4
    expected = 6

    # Prepare
    mock_a = mocker.patch.object(A, 'further_process_nbr', autospec=True)

    # Exercise
    B().process_nbr(nbr)

    # Assert
    assert mock_a.call_args_list[0].args[1] == expected # This is working, but not exactly a nice way
    # mock_a.assert_called_once_with(expected) something like this is basically what I would like to do

标签: pythonunit-testingpython-mockpytest-mock

解决方案


实际上你看到的结果是正确的,在:

assert (<a.A object at 0x000001628C6878B0>, 2) == (2,)

你在元组的第一个元素中看到的是self参数,因为你在类中模拟了方法,所以它也接收self.

要使用 assert_call_once_with 进行检查,您可以使用 mocker.ANY,它将接受任何内容:

mock_a.assert_called_once_with(mocker.ANY, nbr)

推荐阅读