pythonautomated-testsgraphqlgraphene-python

Mocking response for GraphQL query resolver from ServiceObject to prevent API calls in the UnitTests


Let's assume that I have the following service object:

class Foo(object):
    def bar(self):
        return ['foo', 'bar']

And this is the schema:

import Foo

class Query(graphene.ObjectType):
    bar = graphene.List(lambda: graphene.String)

    def resolve_bar(self, info):
        return Foo().bar()

I am trying to test if the GraphQL Schema is correctly calling the method bar in its query resolver. So, we have this piece of code in the tests:

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

Why I am using mocks?

In the original ServiceObject class it makes some API calls to another service, which is already tested in a isolated way. And in this case, I only want to test if the GraphQL query bar is calling a method which will return its supposed object.

The problem

When I mock the response that the service object returns as in the above code, and make the Graphene Client test runs the query, it gives me the 'non-mocked' response. In other words, it is actually calling the original method provided by the service object class and making the API calls, which shouldn't be performed. However, when I instantiate and run the ServiceObject class itself, it is correctly mocked and returns the ['baz', 'qux'] array, not going through the API calls.

Do someone have an ideia of what I am doing wrong?

Or GraphQL Client responses shouldn't be mocked at all? Is there any approach that I can use instead of mocking it?

I already looked all over internet to see how people do that, but I couldn't manage to find any possible solutions.


Solution

  • So, the problem is:

    My patch is wrong. I should patch the callsite, not the definition site. In this case, it will be: @patch('MySchema.Foo') to accomplish the mocking of the callsite.

    To prove that

    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
    

    Thanks to jkimbo who came on the rescue when I asked in the Graphene-Python Github repository.