我有一个python文件a.py
,其中包含两个类A
和B
。
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'>
我在哪里做错了?
答案 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)
我更喜欢pytest和mocker 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'
这就是我达到上述完整测试方法的方式。