我使用MagicMock测试网络应用中的功能。该功能直接从模块导入。
预期的行为是:当被调用的函数被调用时,它会调用第三方api(但我嘲笑我的测试)。返回一个字典,测试中的函数将其插入到一个对象中并返回该对象。
当我使用nosetests运行特定的测试模块时,它可以正常工作。
当我使用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
你能帮我理解为什么结果不一致吗?
修改
新信息 - 如果我直接在模块上使用nosetests,我测试的函数将模拟的Facepy字典值作为unicode(如预期的那样)访问。如果我使用nosetests来发现测试,或者如果我使用下面的dm03514发布的解决方案并直接运行测试,该函数将从模拟的facepy API访问字典作为Magic Mock实例。意思是,访问dict的每个结果都是Magic Mock实例。
令我感到困惑,因为我将return_value(在所有测试中)设置为字典。
答案 0 :(得分:2)
对不起漫长的一天,因此无法在心理上解析为什么事情按目前的方式运作:p
但要解决它,无论测试执行的位置如何,它都会以相同的方式执行,facepy
模块中patch user_service
导入。
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
模块。
答案 1 :(得分:0)
我的问题是对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')