Python返回MagicMock对象而不是return_value

时间:2016-07-05 08:48:13

标签: python python-unittest magicmock

我有一个python文件a.py,其中包含两个类AB

class A(object):
    def method_a(self):
        return "Class A method a"

class B(object):
    def method_b(self):
        a = A()
        print a.method_a()

我想通过模仿method_b在课堂B中对A进行单元测试。以下是文件testa.py的内容:

import unittest
import mock
import a


class TestB(unittest.TestCase):

    @mock.patch('a.A')
    def test_method_b(self, mock_a):
        mock_a.method_a.return_value = 'Mocked A'
        b = a.B()
        b.method_b()


if __name__ == '__main__':
    unittest.main()

我希望输出中得到Mocked A。但我得到的是:

<MagicMock name='A().method_a()' id='4326621392'>

我在哪里做错了?

2 个答案:

答案 0 :(得分:41)

当您private boolean drainOutputBuffers() { MediaCodec.BufferInfo buffInfo = new MediaCodec.BufferInfo(); int outputBufferIndex = codec.dequeueOutputBuffer(buffInfo, TIMEOUT_OUTPUT_BUFFER_MEDIA_CODEC); if (outputBufferIndex >= 0) { codec.releaseOutputBuffer(outputBufferIndex, true); return true; } switch (outputBufferIndex) { case MediaCodec.INFO_TRY_AGAIN_LATER: LOG.debug("Could not dequeue output buffer. Try again later"); break; case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED: LOG.warn("The output format has changed."); break; case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED: LOG.warn("The output buffers has changed."); break; default: LOG.warn("The output buffer index was negative: {}", outputBufferIndex); } return false; } 时,您正在使用@mock.patch('a.A')替换测试代码中的课程A

mock_a中,您可以设置B.method_b,现在是a = A() - 即a = mock_a()a的{​​{1}}。由于您尚未指定此值,因此它是常规return_value;这个也没有配置,因此在调用方法时会得到默认响应(另一个mock_a)。

相反,您要配置 MagicMock MagicMock以获得适当的方法,您可以这样做:

return_value

或者,可能更明确地说:

mock_a

您的代码可以用于mock_a().method_a.return_value = 'Mocked A' # ^ note parentheses (分配类,而不是创建实例),因为mock_a.return_value.method_a.return_value = 'Mocked A' 会触发您的模拟方法。

答案 1 :(得分:-2)

我更喜欢pytestmocker fixture。这是使用pytest和嘲笑者的相同测试:

import a


class TestB:
    def test_method_b(self, mocker):
        mock_A = mocker.MagicMock(name='A', spec=a.A)
        mocker.patch('a.A', new=mock_A)
        mock_A.return_value.method_a.return_value = 'Mocked A'

        b = a.B()
        b.method_b()

您可能会发现我编写测试的方式比测试本身更有趣-我创建了python library来帮助我使用语法。

这是我以系统的方式解决您的问题的方式:

我们从您想要的测试和我的帮助程序库开始:

import a

from mock_autogen.pytest_mocker import PytestMocker


class TestB:
    def test_method_b(self, mocker):
        # this would output the mocks we need
        print(PytestMocker(a).mock_classes().prepare_asserts_calls().generate())

        # your original test, without the mocks
        b = a.B()
        b.method_b()

现在测试不会做很多,但是打印输出很有用:

# mocked classes
mock_A = mocker.MagicMock(name='A', spec=a.A)
mocker.patch('a.A', new=mock_A)
mock_B = mocker.MagicMock(name='B', spec=a.B)
mocker.patch('a.B', new=mock_B)
# calls to generate_asserts, put this after the 'act'
import mock_autogen
print(mock_autogen.generator.generate_asserts(mock_A, name='mock_A'))
print(mock_autogen.generator.generate_asserts(mock_B, name='mock_B'))

现在,我要在调用A之前放置B()的单个模拟,然后在调用generate_asserts之后放置一个模拟,就像这样(不需要以前的打印,因此我删除了它):

def test_method_b(self, mocker):
    # mocked classes
    mock_A = mocker.MagicMock(name='A', spec=a.A)
    mocker.patch('a.A', new=mock_A)

    # your original test, without the mocks
    b = a.B()
    b.method_b()

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

执行此测试后,我们获得了一些宝贵的意见:

assert 1 == mock_A.call_count
mock_A.assert_called_once_with()
mock_A.return_value.method_a.assert_called_once_with()
mock_A.return_value.method_a.return_value.__str__.assert_called_once_with()

前两行验证A模拟是否已初始化一次,且没有参数。第三行验证method_a是否被调用,而第四行可能对您最有帮助,并且可以为您节省很多时间来自行解决:

mock_A.return_value.method_a.return_value.__str__.assert_called_once_with()

您看到method_a的返回值已与str一起使用(由于print函数)。将其替换为所需的字符串非常简单:

mock_A.return_value.method_a.return_value = 'Mocked A'

这就是我达到上述完整测试方法的方式。