简体   繁体   English

如果使用不同的属性多次调用方法,如何模拟方法?

[英]How to mock method if it is getting called multiple times with different attributes?

I am writing unit tests for my Python and Fabric based code.我正在为基于 Python 和 Fabric 的代码编写单元测试。 I have following method which in turn calls sudo method of Fabric API multiple times with different arguments.我有以下方法,它依次使用不同的参数多次调用 Fabric API 的sudo方法。 I would like to know how to call assert on mock sudo object.我想知道如何在模拟sudo对象上调用断言。

**main_file.py**

from fabric.api import sudo

def do_something(path_to_file_to_be_copied, destination_path):
    # remove file if already exists
    sudo('rm ' + path_to_file_to_be_copied, warn_only=True)
    sudo('cp ' + path_to_file_to_be_copied + ' ' + destination_path)

I have written test file as below :我已经编写了如下测试文件:

**test_main_file.py**

import main_file

class MainFileTest(unittest.TestCase):

    @mock.patch('main_file.sudo')
    def test_do_something(self, mock_sudo):
        file_path = '/dummy/file/path.txt'
        dest_dir = '/path/to/dest/dir'
        main_file.do_something(file_path, dest_dir)
        mock_sudo.assert_called_with('rm ' + file_path)

Above test fails because mocked object remembers only last call.上面的测试失败,因为模拟对象只记得最后一次调用。 that is, if I write mock_sudo.assert_called_with(cp + file_path + ' ' + dest_dir) then test fails.也就是说,如果我写mock_sudo.assert_called_with(cp + file_path + ' ' + dest_dir)然后测试失败。

How can I assert both the calls to sudo ?如何断言对sudo两个调用?

Try assert_any_call which asserts whether there has been any call, not just the most recent one.尝试assert_any_call断言是否有任何调用,而不仅仅是最近的调用。

Or, you can use call_args_list to get the list of args the mock has been called with.或者,您可以使用call_args_list来获取已调用模拟的 args 列表。

assert_has_calls will do the job for you. assert_has_calls将为您完成这项工作。

assert_has_calls : assert the mock has been called with the specified calls. assert_has_calls :断言已经使用指定的调用调用了模拟。 The mock_calls list is checked for the calls.检查 mock_calls 列表中的调用。
If any_order is true then the calls can be in any order, but they must all appear in mock_calls.如果 any_order 为真,则调用可以按任何顺序排列,但它们必须全部出现在 mock_calls 中。

import main_file
class MainFileTest(unittest.TestCase):

    @mock.patch('main_file.sudo')
    def test_do_something(self, mock_sudo):
        file_path = '/dummy/file/path.txt'
        dest_dir = '/path/to/dest/dir'
        main_file.do_something(file_path, dest_dir)
        mock_sudo.assert_has_calls(['rm ' + file_path,
                                    'cp' + file_path + ' ' + dest_dir],
                                     any_order=True)

I wrote a helper library to automatically generate the asserts for me.我写了一个帮助库来自动为我生成断言。

Add those lines to print the correct asserts for your case, right after main_file.do_something(file_path, dest_dir) :添加这些行以在main_file.do_something(file_path, dest_dir)之后为您的案例打印正确的断言:

import mock_autogen.generator
print(mock_autogen.generator.generate_asserts(mock_sudo))

You would get the following output:你会得到以下输出:

from mock import call

assert 2 == mock_sudo.call_count
mock_sudo.assert_has_calls(
    calls=[call('rm /dummy/file/path.txt', warn_only=True),
           call('cp /dummy/file/path.txt /path/to/dest/dir'), ])

No need to guess anymore, use mock-generator :)无需再猜测,使用模拟生成器:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM