Python патч макет, кажется, вызывается, но не удается подтвердить

Я использую Python 2.6.6

То, что я пытаюсь сделать, это заменить создание объекта на Mock, чтобы убедиться, что сделаны правильные вызовы. Должно быть простым.

Мой модуль:

import dir.SubModule

class Cls( object ):
    def Start( self ):
        self.__obj = dir.SubModule.SubCls()
        self.__obj.foo()

Мой тест:

import MyModule
import unittest
from mock import Mock, MagicMock, patch

class MyTest( unittest.TestCase ):
    def setUp( self ):
        self.uut = MyModule.Cls()

    def test_one( self ):
        with patch( 'dir.SubModule.SubCls', spec=True ) as mockObj:
            print "mock calls before"
            print mockObj.mock_calls
            self.uut.Start()

            print "called: "      + str( mockObj.called )
            print "foo called: " + str( mockObj.foo.called )
            print "call_count: "  + str( mockObj.call_count )
            print "call_args: "   + str( mockObj.call_args )
            print "args_list: "   + str( mockObj.call_args_list )
            print "mock calls:\n" + str( mockObj.mock_calls )
            print "method calls:\n " + str( mockObj.method_calls )

Выход:

mock calls before:
[]
called: True
foo called: False
call_count: 1
call_args: call()
args_list: [call()]
mock calls:
[call(), call().foo()]
method calls:
[]

И все же тест не пройден:

AssertionError: Expected call: foo()
Not called

Я не понимаю, как макет может сообщить, что звонки были сделаны, но я не могу утверждать, что они были вызваны. Что мне не хватает?

РЕДАКТИРОВАТЬ: После добавления в отчет всех метрик, кажется, есть что-то фундаментальное, что я неправильно понимаю насчет Python Mocks. Если foo() есть в списке вызовов, то почему счетчик вызовов только 1, и почему foo.called сообщает "False"?

2 ответа

Решение

mockObj.foo никогда не вызывается в этом тесте. self.uut.Start() звонки mockObj, создавая новый макет, а затем называет это макет foo метод. Если вы хотите утверждать, что этот вызов произошел, вам нужно получить доступ к правильному объекту:

mockObj.return_value.foo.assert_called_with()

Вот ссылка: ссылка

Мое простое исправление:

with patch( 'class' ) as mockCreator:
    mockObj = mockCreator.return_value

Тогда я могу использовать 'mockObj' волей-неволей.

Я наткнулся на связанное решение на прошлой неделе, когда я впервые узнал о мошенничестве - слишком рано, чтобы информация полностью погрузилась.

Синтаксис mock assert имеет множество причуд. Чтобы справиться с этим, я написал вспомогательную библиотеку для генерации утверждений для меня.

Вот как вы могли бы использовать его для своего метода тестирования:

import MyModule
import unittest
from mock import patch

class MyTest( unittest.TestCase ):
    def setUp( self ):
        self.uut = MyModule.Cls()

    def test_one( self ):
        with patch( 'dir.SubModule.SubCls', spec=True ) as mockObj:
            self.uut.Start()

            # calls to generate_asserts, put this after the 'act'
            import mock_autogen.generator
            print(mock_autogen.generator.generate_asserts(mockObj))

Вы получите следующий результат:

assert 1 == mockObj.call_count
mockObj.assert_called_once_with()
mockObj.return_value.foo.assert_called_once_with()

Что соотносится с __init__ звонок, затем звонок foo вновь созданного объекта.

Так что больше не нужно выяснять точный синтаксис самостоятельно, просто примените инструмент:)

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