Как смоделировать метод, если он вызывается несколько раз с разными атрибутами?

Я пишу юнит-тесты для моего Python а также Fabric основанный код. У меня есть следующий метод, который в свою очередь вызывает sudo Метод Fabric API несколько раз с разными аргументами. Я хотел бы знать, как позвонить утверждать на макете 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)

Я написал тестовый файл, как показано ниже:

**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)

Вышеприведенный тест не пройден, потому что смоделированный объект помнит только последний вызов. то есть если я напишу mock_sudo.assert_called_with(cp + file_path + ' ' + dest_dir) тогда тест не пройден.

Может кто-нибудь, пожалуйста, скажите, как я могу утверждать оба звонка sudo?

2 ответа

Решение

Пытаться assert_any_call который утверждает, что был какой-либо звонок, а не только самый последний.

Или вы можете использовать call_args_list чтобы получить список аргументов, был вызван макет с.

assert_has_calls сделает всю работу за вас.

assert_has_calls: утверждать, что макет был вызван с указанными вызовами. Список mock_calls проверяется на наличие вызовов.
Если any_order имеет значение true, то вызовы могут быть в любом порядке, но все они должны появляться в 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):

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:)

Другие вопросы по тегам