在测试依赖第三方库的代码时进行模拟或不模拟

时间:2012-01-20 14:44:55

标签: python unit-testing mocking doctest

我编写了一个函数,它基本上隐藏了使用pySnmp库发送SNMP消息的复杂性,它看起来像:

snmpWalk(host,oid):
    from pysnmp.entity.rfc3413.oneliner import cmdgen
    cg = cmdgen.CommandGenerator()
    comm_data = cmdgen.CommunityData('my-manager','public')
    transport = cmdgen.UdpTransportTarget((host,161))
    variables = oid
    return cg.nextCmd(comm_data,transport,variables)

我是单元测试的新手,我试图使用minimock为这段代码编写一个单元测试作为doctest,这就是我提出的:

#Setup the mocks
>>> from minimock import mock, Mock
>>> cmdgen.CommandGenerator = Mock('cmdgen.CommandGenerator')
>>> cmdgen.CommunityData = Mock('cmdgen.CommunityData')
>>> cmdgen.UdpTransportTarget = Mock('cmdgen.UdpTransportTarget')
>>> cgMock = Mock('cgMock')
>>> cmdgen.CommandGenerator.mock_returns = cgMock
>>> cmdgen.CommunityData.mock_returns = 1
>>> cmdgen.UdpTransportTarget.mock_returns = 2
>>> cgMock.nextCmd.mock_returns = (1,2,3,4)
#run the test
>>> PrinterMonitor.SnmpWalk('192.0.0.1','1.1.1.1.1.1.1') 
Called cmdgen.CommandGenerator()
Called cmdgen.CommunityData('my-manager', 'public')
Called cmdgen.UdpTransportTarget(('192.0.0.1', 161))
Called cgMock.nextCmd(1, 2, (1, 1, 1, 1, 1, 1, 1))
(1, 2, 3, 4)

所以我运行这个测试并且它运行良好,但我的问题是,我是否真的需要在模拟第三方库的每个方面进行所有这些努力?在我看来,我需要模拟的最小值是最后一行cg.nextCmd(comm_data,transport,variables),因为我实际上并不想在单元测试中开始向打印机发送消息,但是对库代码的其他调用应该让我保持一致结果,取决于我传递给他们的东西。我可以确保我的代码与库正确交互(即确保它通过在传递给模拟cg.nextCmd(...)调用的对象上声明它来正确地将host参数传递给传输变量?

1 个答案:

答案 0 :(得分:0)

你需要经历所有这些努力吗?没有。

要测试使用您的snmpWalk()函数的代码,最好模拟包含该函数的类。我不知道Python术语,但在Java术语中,我会将snmpWalk()放在一个接口中,然后有一个pySnmp实现和任意数量的模拟/测试实现。调用snmpWalk()的代码不应该关心任何内部细节,它只关心返回值,因此这是你想要模拟的级别。

为了测试pySnmp实现类本身,可以模拟出库调用,但这是很多工作并且风险很大,因为你的模拟必须非常接近地模拟库。我会坚持真正的电话。如果这意味着触发真正的打印机请求,请不要经常运行该测试 - 或者查看是否有办法配置库以打印到虚拟/伪造打印机。