mercredi 3 janvier 2018

How to mock Python classes when nested several dependencies deep

If I have the following architecture...

MainClass.py

class MainClass(object):
    def do_some_stuff(self):
        dependent_class = DependentClass()
        dependent_class.do_dependent_stuff()



DependentClass.py

class DependentClass(object):
    def do_dependent_stuff(self):
        print "I'm gonna do production stuff that I want to mock"
        print "Like access a database or interact with a remote server"



class MockDependentClass(object):
    def do_dependent_stuff(self):
        print "Respond as if the production stuff was all successful."

and I want to call main_class.do_some_stuff during testing but, during its execution, I want instances of DependentClass replaced with MockDependentClass how can I do that pythonically using best practices.

Currently, the best thing I could come up with is to conditionally instantiate one class or the other based on the presence/value of an environment variable. It certainly works but is pretty dirty.

I spent some time reading about the unittest.mock and mock.patch functions and they seem like they might be able to help but each description that I could wrap my head around seemed to be a little different than my actual use case.

The key is that I don't want to define mock return values or attributes but that I want the namespace changed, globally, I guess, such that when my application thinks it is instantiating DependentClass it is actually instantiating MockDependentClass.

The fact that I can't find any examples of anyone doing exactly this means one of two things:

  1. It's because I'm doing it in a very dumb/naive way.
  2. I'm doing something so genius no else has ever encountered it.

... I assume it's number 1...

Full disclosure, unit testing is not something with which I am skilled. It's an effort that my internal tools development team is trying to catch up to step our game up a bit. It's possible that I'm not thinking about testing correctly.

Any thoughts would be most welcome. Thank you, in advance!

Aucun commentaire:

Enregistrer un commentaire