Magic Mock терпит неудачу, когда тестирование носа обнаруживает тесты

Я использую MagicMock для тестирования функции в веб-приложении. Функция импортируется непосредственно из модуля.

Ожидаемое поведение: при вызове тестируемой функции она вызывает сторонний API (но я проверяю это для своего теста). Это возвращает словарь, а тестируемая функция вставляет его в объект и возвращает объект.

Это прекрасно работает, когда я использую тесты носа для запуска этого конкретного модуля тестов.

Когда я использую тесты носа, чтобы обнаружить и запустить тесты в моем 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

Можете ли вы помочь мне понять, почему результат противоречив?

РЕДАКТИРОВАТЬ

Новая информация - если я использую тесты носа непосредственно в модуле, тестируемая функция получает доступ к значениям словаря Facepy в качестве юникода (как и ожидалось). Если я использую тестирование носа для обнаружения тестов или если я использую решение, опубликованное dm03514 ниже, и запускаю тесты напрямую, функция обращается к словарю из смоделированного API-интерфейса facepy как экземпляры Magic Mock. Это означает, что каждый результат доступа к диктовке является экземпляром Magic Mock.

Это сбивает с толку, так как я устанавливаю return_value (во всех тестах) в качестве словаря.

2 ответа

Извините за долгий день, поэтому не могу по-настоящему мысленно разобраться, почему все работает так, как сейчас: p

Но решить ее так, чтобы она работала одинаково, независимо от того, где выполняется тест, - это исправить facepy импорт в 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 модуль.

Моей проблемой было недопонимание того, как MagicMock обрабатывает словари. Вы должны объявить его __getitem__ имущество.

Я думаю, что "несоответствие", которое я упомянул, было скорее случайностью, что мои тесты работали вообще.

Это в значительной степени заимствует из ответа @dm03514.

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')
Другие вопросы по тегам