4

I want to write a mock for a library object without inheriting from it in order to properly test, however without having to stub all non used functions of the original object.

To be specific I want to write a ContextMock for the invoke library.

class ContextMock:
    ...

The main problem here is that I therefor call a @task function which then calls my code that I want to test. However the @task decorator checks whether the context object is an instance of a Context, like this:

def __call__(self, *args, **kwargs):
    # Guard against calling tasks with no context.
    if not isinstance(args[0], Context):
        err = "Task expected a Context as its first arg, got {} instead!"
        # TODO: raise a custom subclass _of_ TypeError instead
        raise TypeError(err.format(type(args[0])))

Therefor my question is, can I somehow change the isinstance function of my ContextMock, or make it look like its an instance of Context without inheriting its attributes? Or would it be possible to somehow mock the isinstance function? How does the default implementation of instancecheck work? Is there perhabs a baseclass attribute that can be overwritten?

I already tried to provide a custom metaclass with an custom instancecheck function, which of course does not work as the instancecheck of the Context is called, right?

Also Note that I'm well aware that any hacky solution should not belong in production code, and is only used for testing.

Edit: To add a generic example of what I want to archive:

class Context:
    pass

class ContextMock: 
    pass

mock = ContextMock

... do magic with mock

assert isinstance(mock, Context)
Manuel S.
  • 63
  • 5
  • A way to archive the wanted behavior is to let the ContextMock inherit from unittest.mock.Mock and then call its constructor with spec=Context. It still would be nice to understand how the Mock is doing it / whether there is a nicer way – Manuel S. Nov 10 '20 at 08:24

0 Answers0