1

I have been writing unit tests for over a year now, and have always used patch.object for pretty much everything (modules, classes, etc).

My coworker says that patch.object should never be used to patch an object in a module (i.e. patch.object(socket, 'socket'), instead you should always use patch('socket.socket').

I much prefer the patch.object method, as it allows me to import modules and is more pythonic in my opinion. Is my coworker right?

Note: I have looked through the patch documentation and can't find any warnings on this subject. Isn't everything an object in python?

vitiral
  • 8,446
  • 8
  • 29
  • 43

3 Answers3

0

There is no such requirement, and yes, everything is an object in Python.

It is nothing more than a style choice; do you import the module yourself or does patch take care of this for you? Because that's the only difference between the two approaches; either patch() imports the module, or you do.

For the code-under-test, I prefer mock.patch() to take care of this, as this ensures that the import takes place as the test runs. This ensures I get a test error state (test failure), rather than problems while loading the test. All other modules are fair game.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • `patch` will automatically import it as long as it is on the python path. – vitiral Aug 27 '15 at 18:02
  • @cloudformdesign: it was a rhetorical question. :-) I meant to say: ask yourself that question to determine what you would prefer. I added a reason to prefer one over the other. – Martijn Pieters Aug 27 '15 at 18:03
  • I decided to just look at the source code for mock and found it to be very simple and readable. I posted a longer answer below. Thanks for the help :) – vitiral Aug 27 '15 at 18:22
0

Looking at the mock source code, it really doesn't look like there is a difference.

To investigate I first looked at def patch and see that it does:

  getter, attribute = _get_target(target)
  return _patch(
     getter, attribute, new, spec, create,
     spec_set, autospec, new_callable, kwargs)

wheras patch.object does the same except: getter = lambda: target

Ok, so what does this _get_target do? It pretty much splits the string and calls _importer on the first part (making an object) and uses the string the same way as get_object.

_importer is a pretty simple mechanism to import from a module (using getattr for every "component"), and pretty clearly just makes an object as well.

So fundamentally, at the source level, there is not really any difference.

Case Closed

vitiral
  • 8,446
  • 8
  • 29
  • 43
-1

These two are the same

@patch.object(provider.Provider, autospec=True)
def test_init(self, mock_provider):
    pass

@patch('provider.Provider', autospec=True)
def test_init(self, mock_provider):
    pass

Which one to choose?

If you already have the class imported, you can use patch.object, it is more readable. If you have to import it just to patch it, then use a string instead.

Gonzalo
  • 752
  • 8
  • 23