Ложный ответ для распознавателя запросов GraphQL из ServiceObject для предотвращения вызовов API в UnitTests
Давайте предположим, что у меня есть следующий сервисный объект:
class Foo(object):
def bar(self):
return ['foo', 'bar']
И это схема:
import Foo
class Query(graphene.ObjectType):
bar = graphene.List(lambda: graphene.String)
def resolve_bar(self, info):
return Foo().bar()
Я пытаюсь проверить, правильно ли схема GraphQL вызывает метод bar
в своем преобразователе запросов. Итак, у нас есть этот кусок кода в тестах:
from MySchema import Query
class TestFooBar(unittest.TestCase):
@patch('Foo')
def test_bar(self, mock_foo):
mock_foo.return_value.bar.return_value = ['baz', 'qux']
my_schema = graphene.Schema(query=Query)
client = Client(self.my_schema)
query = '''
query {
bar()
}
'''
executed = self.client.execute(query)
#some attributes that I want to assert
assertTrue(mock_foo.called) # returns False
Почему я использую издевательства?
В исходном классе ServiceObject он выполняет некоторые вызовы API для другой службы, которая уже тестируется изолированно. И в этом случае я только хочу проверить, если запрос GraphQL bar
вызывает метод, который вернет предполагаемый объект.
Эта проблема
Когда я высмеиваю ответ, который возвращает сервисный объект, как в приведенном выше коде, и заставляю тест клиента Graphene выполнить запрос, он дает мне "немодированный" ответ. Другими словами, это фактически вызов исходного метода, предоставленного классом объекта службы, и выполнение вызовов API, которые не должны выполняться. Однако, когда я создаю экземпляр и запускаю сам класс ServiceObject, он корректно проверяется и возвращает ['baz', 'qux']
массив, не проходящий через вызовы API.
У кого-то есть представления о том, что я делаю неправильно?
Или ответы клиента GraphQL вообще не должны поддразнивать? Есть ли какой-нибудь подход, который я могу использовать вместо насмешек?
Я уже просмотрел весь интернет, чтобы увидеть, как люди это делают, но мне не удалось найти каких-либо возможных решений.
2 ответа
Итак, проблема в том, что:
мой patch
неправильно. Я должен исправить патч, а не сайт определения. В этом случае это будет: @patch('MySchema.Foo')
выполнить издевательство над паролем.
Чтобы доказать это
from MySchema import Query
class TestFooBar(unittest.TestCase):
@patch('MySchema.Foo')
def test_bar(self, mock_foo):
mock_foo.return_value.bar.return_value = ['baz', 'qux']
my_schema = graphene.Schema(query=Query)
client = Client(self.my_schema)
query = '''
query {
bar()
}
'''
executed = self.client.execute(query)
assertTrue(mock_foo().bar.called) # now returns True
Спасибо jkimbo, который пришел на помощь, когда я спросил в репозитории Graphene-Python Github.
Я знаю, что этот вопрос касается Graphene , но у меня была такая же проблема (насмешка над распознавателем graphql) с Ariadne , и я написал это решение для других, таких как я, у которых нет доступа к достаточному количеству документов о модульных тестах graphql с ariadne.
Как сказано в принятом ответе, имитирующего распознавателя недостаточно, и graphql по-прежнему вызывает неискаженный распознаватель. Поэтому мы должны изменить схему, чтобы вызывать эту новую функцию вместо основного преобразователя. И, в моем случае, измените URL-адрес django, чтобы использовать новую исполняемую схему.
from .urls import urlpatterns
with patch('path.to.my_resolver') as mocked_resolver:
query = QueryType()
query.set_field(mocked_field, mocked_resolver)
mocked_resolver.return_value = mocked_return_value
my_schema = make_executable_schema(my_base_schema, query, snake_case_fallback_resolvers)
urlpatterns.clear() # remove main urls
urlpatterns.append(path('graphql/', GraphQLView.as_view(schema=my_schema), name='graphql'))
Примечание: snake_case_fallback_resolvers из-за обработки декоратора convert_kwargs_to_snake_case .