It would be great if there was a support for using mock in two steps, like this; {{{ class TestSth(TestCase): def setUp(self): self._original_state = mock.setup_mocking("sys.stdin") def tearDown(self): mock.teardown_mocking(self._original_state) }}}
Comment #1
Posted on Jun 10, 2010 by Helpful MonkeyWhat would that actually do? (Why reuse mocks anyway - they're not expensive to create?)
Comment #2
Posted on Jun 10, 2010 by Massive Birdnot for reuse mocks, rather to get rid of repetitive mocking of the same resource. That would be useful for older Python versions (with no class decorators).
Comment #3
Posted on Jun 10, 2010 by Massive Birdboth tickets (this and #31) are for situations when every test method needs common patching.
Also, for some reason, google doesn't let me mark it a en enhancement/feature-request
Comment #4
Posted on Jun 10, 2010 by Helpful MonkeyI kind of see what you mean, but have trouble imagining how the code might look. Perhaps you could explain to me what you think "setup_mocking" and "teardown_mocking" should do. (Or even better write a patch - but an explanation would be fine.)
Comment #5
Posted on Jun 10, 2010 by Helpful Monkey(No comment was entered for this change.)
Comment #6
Posted on Jun 10, 2010 by Helpful MonkeyAh. So, mock.setup_mock('sys.stdin') would patch sys.stdin and return the mock (presumably with some stored state so that teardown_mock can unpatch automatically).
That sounds fine - although "setup_mock" isn't quite the right name as it is more to do with patching. That sounds useful, but how would you ensure that the unpatching is done on test failure? Is that just up to the user to ensure?
I'd definitely be open to a patch for this (with docs and tests of course) and we can debate the names later...
Comment #7
Posted on Jun 10, 2010 by Massive BirdMy use case is similar to one for class decorator: Say you have a an object that hits the web on each instantiation. In order to make test reliable you want to patch this behaviour, but there's ton of logic that you need to test, so your @mock.patch() becomes painfully repetitive. Both tickets propose a feature covering this use case. What I had in mind was to prepare series of patches, store it in self._original_state and then restore in teardown. The default setup/teardown behaviour would be used for basic test failure safety.
Comment #8
Posted on Jun 10, 2010 by Massive BirdI'd definitely be open to a patch for this
Great :) I switched from preparing patches first to reporting issue first - when I implemented unittest2.collector yesterday, I found out you did it two hours before :)
Comment #9
Posted on Jun 12, 2010 by Helpful Monkey(No comment was entered for this change.)
Comment #10
Posted on Jun 12, 2010 by Massive BirdHere's the overview of the API that's going to get implemented {{{ class TestSomething(unittest.TestCase): def setUp(self): self.patches = mock.patch.setup("sys.stdin", # you can pass a string. this would work like patch("sys.stdin") mock.patch("sys.stdout"), # you can pass a patch decorator object mock_stderr=mock.patch.object(sys, "stderr")) # you can pass patch.object decorator instance, but you need to give keyword argument for that if you want to access it def testSomething(self): self.patches["sys.stdin"] self.patches["sys.stdout"] self.patches["mock_stderr"]
def tearDown(self):
self.patches.unpatch()
}}}
Comment #11
Posted on Jun 12, 2010 by Helpful MonkeyI'm not sure I like "unpatch" as method name. How about "restore"?
The patches object returned by patch.setup could (should?) be a context manager, so you can use it in a with statement and have "unpatch" (or "restore") called automatically for you:
{{{ patches = patch.setup('sys.stdin', 'sys.stdout') with patches: ... }}}
Comment #12
Posted on Jun 12, 2010 by Massive BirdI'm not sure I like "unpatch" as method name. How about "restore"?
I don't like it either. I thought about "restore", but it wouldn't make much sense semantically: that would read "restore the patches" rather than "restore the originals".
What about clean() or cleanup()?
Comment #13
Posted on Jun 12, 2010 by Helpful MonkeyI don't think "restore" implies "restore the patches", "cleanup" is fine - but perhaps we should go with "teardown" to be symmetrical with "setup"? Finding a nice symmetrical pair would be ideal. "setup" and "teardown" have their own meaning in unit testing so it is perhaps not ideal to re-use them (?) - but they're not too bad.
Comment #14
Posted on Jun 13, 2010 by Helpful Monkey(No comment was entered for this change.)
Comment #15
Posted on Oct 15, 2010 by Helpful MonkeyActually unpatch and teardown are both fine as names.
Comment #16
Posted on Oct 15, 2010 by Swift CatI use the following pattern:
class MyTest(TestCase): def setUp(self): self._metamock = patch('myapp.models.meta') self.metamock = self._metamock.enter() self.metamock.Session.query.return_value = []
def tearDown(self):
del self.metamock
self._metamock.__exit__()
On IRC fuzzyman suggested patch.setup and patch.teardown, which I like, it makes it clear what it's meant for. I also like the self.patches above, but would like an API for single mocks as well like in my pattern above. Though that could also be done with a manual assignment like self.metamock = self.patches["myapp.models.meta"]
Comment #17
Posted on Nov 12, 2010 by Helpful MonkeyA work colleague asked for this today. Definitely something we should support. Clean API still needs to be worked out.
I think I prefer adding the patches with a series of calls rather than one long call doing multiple patches. Something along the lines of:
{{{ def setUp(self): self.patches = mock.patcher() self.patches.add(*args) self.patches.add(*args) }}}
The mocks could then be accessed by indexing self.patches, either positionally or by name.
{{{
def tearDown(self): self.patches.unpatch() }}}
Comment #18
Posted on Nov 12, 2010 by Helpful MonkeyMy colleague would like add to return the mock to avoid having to index the patcher.
Note that we would need patcher.add_object (and patcher.add_dict) as well.
Perhaps patcher.add_object and add_dict could require you to specify a name and we could not provide indexing by position?
Comment #19
Posted on Nov 12, 2010 by Helpful MonkeyNote that in the Hg repo (and will be in 0.7.0b4) patch objects now have start / stop methods. These are only aliases for enter / exit but make it a bit prettier to use in this way. Calling start returns the mock (default behaviour of enter anyway). So you can do:
{{{
def setUp(self): self.patch = patch('something.foo') self.mock_foo = self.patch.start()
def tearDown(self): self.patch.stop() }}}
This works with patch, patch.object and patch.dict.
Comment #20
Posted on Dec 6, 2010 by Helpful MonkeyNote that patch objects have start and stop methods in 0.7.0. A nice API for multiple patches in setUp / tearDown would still be nice.
Comment #21
Posted on May 28, 2011 by Helpful Monkey(No comment was entered for this change.)
Comment #22
Posted on Nov 30, 2011 by Quick LionI've drafted an implementation of this here: http://code.google.com/r/wolfgangschnerring-setupteardown/source/browse
If there is interest, I'll try to add to the documentation, too.
This is my first patch to mock
, so any feedback is appreciated.
Comment #23
Posted on Dec 9, 2011 by Happy OxI think the "patcher" looks pretty straight forward. I think there should be a way to access the individual mocks, though. Otherwise you end up storing them manually again, which kinda defeats the purpose of managing them together. Maybe with a "name" attribute in the add_* methods and simple dict like access?
Comment #24
Posted on Dec 29, 2011 by Helpful MonkeyI agree with florian that some way of accessing the mocks after creation would be useful.
Comment #25
Posted on Nov 14, 2013 by Helpful Monkeypatcher.start() and patcher.stop() allow you to use patch in setUp and tearDown. Perhaps a way of doing multiple patches in a single call would still be useful?
Status: Accepted
Labels:
Type-Enhancement
Priority-Low