Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Test Behavior with Patch (Flask)

I am trying to patch methods in my flask api but it appears that the method call is not being replaced. Does app.test_client() do something under the hood that I am missing.

For example if I run

 @patch('k.stats.mstats')
  def test_ps(self, mstats):
    mstats.return_value = (1, 2, 3)
    rv = self.app.get('/ps/')

and I run through the debugger to the point below:

@app.route('/ps/', methods=['GET'])
def ps():
  import pdb
  pdb.set_trace()
  mstats()

and inspect mstats, I will get back the function that is unmocked.

However, if I run from k.stats import mstats from the breakpoint, I get back the mocked method that I am looking for.

How do I ensure that the mocked method gets called?

like image 870
James Lam Avatar asked Apr 23 '15 21:04

James Lam


1 Answers

This is a pretty confusing concept, but the documentation of patch tries its best to explain it.

patch works by (temporarily) changing the object that a name points to with another one. There can be many names pointing to any individual object, so for patching to work you must ensure that you patch the name used by the system under test.

The basic principle is that you patch where an object is looked up, which is not necessarily the same place as where it is defined.

This is why you're able to observe the mocked object when you decide to inject it in; you're observing the patched reference where it's looked up at that moment.

The example does an okay job of explaining what's going on there, but I'll try to clarify.

Let's say that mstats lives in module stats. You're importing it through from stats import mstats in module use_stats.

You're going to want to mock it in use_stats, since that's its place of reference.

@patch('use_stats.mstats')
def test_stats(self, mstats):
    pass
like image 131
Makoto Avatar answered Oct 05 '22 17:10

Makoto