【问题标题】:Magic Mock fails when nosetest discovers tests当 nosetest 发现测试时,Magic Mock 失败
【发布时间】:2017-03-06 01:15:53
【问题描述】:

我正在使用 MagicMock 测试网络应用程序中的功能。该函数是直接从模块中导入的。

预期的行为是:当被测试的函数被调用时,它会调用第三方 api(但我在为我的测试模拟这个)。这将返回一个字典,而被测函数将其插入一个对象并返回该对象。

当我使用鼻子测试来运行特定的测试模块时,效果很好。

当我使用nosetests 在我的test/unit/ 文件夹中发现和运行测试时,测试无法按预期工作。相反,模拟 API 返回一个 NoneType,而被测试的函数返回一个 Magic Mock 实例。

测试:

def test_get_user_facebook_data_1(self):
    facebook_oauth_response = {u'name': u'Jack Jacker', u'email': u'jack@jack.jack', u'id': u'sd5Jtvtk6'}
    facepy.GraphAPI.get = MagicMock(return_value=facebook_oauth_response)

    user_facebook_data = user_service.get_user_facebook_data('bogus_facebook_oauth_access_token')

    self.assertEquals(user_facebook_data._facebook_oauth_id, u'sd5Jtvtk6')
    self.assertEquals(user_facebook_data._email, u'jack@jack.jack')
    self.assertEquals(user_facebook_data._full_name, u'Jack Jacker')

正在测试的函数(在user_service 模块中):

def get_user_facebook_data(facebook_access_token):

    '''
    With a user's FB access token, retrieve their credentials to either create a new account or login. Create a user object from the user model,         but don't save
    '''

    try:
        graph = facepy.GraphAPI(facebook_access_token)
        facebook_data = graph.get('me?fields=id,name,email')
    except facepy.exceptions.OAuthError:
        raise errors.FacebookAccessTokenInvalidError()

    user = user_model.User()

    try:
        facebook_oauth_id = facebook_data[u'id']
        user.set_new_fb_oauth(facebook_oauth_id)
    except KeyError:
        raise errors.OauthNoIdError()

    try:
        email = facebook_data[u'email']
        user.set_new_email(email)
    except KeyError:
        pass

    try:
        full_name = facebook_data[u'name']
        user.set_new_full_name(full_name)
    except KeyError:
        pass

    return user

你能帮我理解为什么结果不一致吗?

编辑

新信息 - 如果我直接在模块上使用鼻子测试,我正在测试的函数会以 unicode 的形式访问模拟的 Facepy 字典值(如预期的那样)。如果我使用nosetests 来发现测试,或者如果我使用下面dm03514 发布的解决方案并直接运行测试,则该函数会从模拟的facepy API 作为Magic Mock 实例访问字典。意思是,访问 dict 的每个结果都是一个 Magic Mock 实例。

这令人困惑,因为我将 return_value(在所有测试中)设置为字典。

【问题讨论】:

  • 更新答案 :) 测试正在修补类上的 get 方法,而不是实例上的方法。可以使用return_value 引用该实例

标签: python unit-testing mocking nose magicmock


【解决方案1】:

对不起,漫长的一天,所以无法真正从精神上分析为什么事情会以目前的方式运行:p

但要解决它,使其无论在何处执行测试都以相同的方式执行,是在 user_service 模块中导入 patch facepy

def test_get_user_facebook_data_1(self):
    facebook_oauth_response = {u'name': u'Jack Jacker', u'email': u'jack@jack.jack', u'id': u'sd5Jtvtk6'}
    with mock.patch('module.path.to.user_service.facepy') as mock_facepy:
      mock_facepy.GraphAPI.return_vaule.get = MagicMock(return_value=facebook_oauth_response)

      user_facebook_data = user_service.get_user_facebook_data('bogus_facebook_oauth_access_token')

      self.assertEquals(user_facebook_data._facebook_oauth_id, u'sd5Jtvtk6')
      self.assertEquals(user_facebook_data._email, u'jack@jack.jack')
      self.assertEquals(user_facebook_data._full_name, u'Jack Jacker')

以上补丁将facepy 本地到user_service 模块。

【讨论】:

  • 我试过这个,谢谢。这看起来像是模拟事物的聪明方法,但我的问题仍然存在(更新了我的问题)。
  • 抱歉,已更新,忘记返回值,现在应该可以使用了。由于图形 API 正在被实例化,mock 需要一些你想在实例上而不是在类上修补 get 的方式。
  • 所以,再次感谢。当我专门使用这个模块运行nosetests时,这确实有效,但是我允许nosetests发现测试的问题仍然存在。不管怎样,return_value 的信息非常有用。
【解决方案2】:

我的问题是对 MagicMock 处理字典的方式存在误解。您需要声明其__getitem__ 属性。

我认为我提到的“不一致”更多是我的测试完全有效的侥幸。

这大量借鉴了@dm03514's answer

def test_get_user_facebook_data_1(self):
    facebook_oauth_response = {u'name': u'Jack Jacker', u'email': u'jack@jack.jack', u'id': u'sd5Jtvtk6'}
    with mock.patch('api.services.user_service.facepy') as mock_facepy:

        # Mocking the response from the facepy.
        # Setting this side effect allows the Mock object to be accessed as a dict.
        def getitem(name):
            return facebook_oauth_response[name]
        mock_oauth = MagicMock()
        mock_oauth.return_value = facebook_oauth_response 
        mock_oauth.__getitem__.side_effect = getitem
        mock_facepy.GraphAPI.return_value.get = mock_oauth

        user_facebook_data = user_service.get_user_facebook_data('bogus_facebook_oauth_access_token')

        self.assertEquals(user_facebook_data._facebook_oauth_id, u'sd5Jtvtk6')
        self.assertEquals(user_facebook_data._email, u'jack@jack.jack')
        self.assertEquals(user_facebook_data._full_name, u'Jack Jacker')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-26
    • 2019-09-14
    • 2021-08-02
    • 2019-01-25
    • 2013-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多