Python的Mock模拟测试介绍(6)

发表于:2014-03-21来源:DiggerPlus作者:DiggerPlus点击数: 标签:模拟测试
在这个例子中,我们甚至不需要补充任何功能,只需创建一个带auto-spec方法的RemovalService类,然后将该实例注入到UploadService中对方法验证。 mock.create_auto

  在这个例子中,我们甚至不需要补充任何功能,只需创建一个带auto-spec方法的RemovalService类,然后将该实例注入到UploadService中对方法验证。

  mock.create_autospec为类提供了一个同等功能实例。这意味着,实际上来说,在使用返回的实例进行交互的时候,如果使用了非法的方法将会引发异常。更具体地说,如果一个方法被调用时的参数数目不正确,将引发一个异常。这对于重构来说是非常重要。当一个库发生变化的时候,中断测试正是所期望的。如果不使用auto-spec,即使底层的实现已经破坏,我们的测试仍然会通过。

  陷阱:mock.Mock和mock.MagicMock类

  mock库包含两个重要的类mock.Mock和mock.MagicMock,大多数内部函数都是建立在这两个类之上的。在选择使用mock.Mock实例,mock.MagicMock实例或auto-spec方法的时候,通常倾向于选择使用 auto-spec方法,因为它能够对未来的变化保持测试的合理性。这是因为mock.Mock和mock.MagicMock会无视底层的API,接受所有的方法调用和参数赋值。比如下面这个用例:

1
2
3
4
class Target(object):
    def apply(value):
        return valuedef method(target, value):
    return target.apply(value)

  我们像下面这样使用mock.Mock实例来做测试:

1
2
3
4
5
6
7
8
class MethodTestCase(unittest.TestCase):
 
    def test_method(self):
        target = mock.Mock()
 
        method(target, "value")
 
        target.apply.assert_called_with("value")

  这个逻辑看似合理,但如果我们修改Target.apply方法接受更多参数:

1
2
3
4
5
6
class Target(object):
    def apply(value, are_you_sure):
        if are_you_sure:            
            return value        
        else:            
            return None

  重新运行你的测试,然后你会发现它仍然能够通过。这是因为它不是针对你的API创建的。这就是为什么你总是应该使用create_autospec方法,并且在使用@patch和@patch.object装饰方法时使用autospec参数。

  真实世界的例子: 模仿一次 Facebook API 调用

  在结束之际,让我写一个更加实用的真实世界的例子, 这在我们的介绍部分曾今提到过: 向Facebook发送一个消息. 我们会写一个漂亮的封装类,和一个产生回应的测试用例.

1
2
3
4
5
6
7
8
import facebookclass 
 
SimpleFacebook(object):
 
    def __init__(self, oauth_token):
        self.graph = facebook.GraphAPI(oauth_token)    def post_message(self, message):
        """Posts a message to the Facebook wall."""
        self.graph.put_object("me", "feed", message=message)

原文转自:http://www.diggerplus.org/archives/2704