derwiki-adroll / mock

Automatically exported from code.google.com/p/mock
BSD 2-Clause "Simplified" License
0 stars 0 forks source link

setup/teardown support #30

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
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)
}}}

Original issue reported on code.google.com by kon...@gmail.com on 10 Jun 2010 at 9:49

GoogleCodeExporter commented 9 years ago
What would that actually do? (Why reuse mocks anyway - they're not expensive to 
create?)

Original comment by fuzzyman on 10 Jun 2010 at 9:51

GoogleCodeExporter commented 9 years ago
not 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).

Original comment by kon...@gmail.com on 10 Jun 2010 at 11:08

GoogleCodeExporter commented 9 years ago
both 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

Original comment by kon...@gmail.com on 10 Jun 2010 at 11:12

GoogleCodeExporter commented 9 years ago
I 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.)

Original comment by fuzzyman on 10 Jun 2010 at 11:12

GoogleCodeExporter commented 9 years ago

Original comment by fuzzyman on 10 Jun 2010 at 11:18

GoogleCodeExporter commented 9 years ago
Ah. 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...

Original comment by fuzzyman on 10 Jun 2010 at 11:22

GoogleCodeExporter commented 9 years ago
My 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.

Original comment by kon...@gmail.com on 10 Jun 2010 at 11:30

GoogleCodeExporter commented 9 years ago
> I'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 :)

Original comment by kon...@gmail.com on 10 Jun 2010 at 11:56

GoogleCodeExporter commented 9 years ago

Original comment by fuzzyman on 12 Jun 2010 at 11:22

GoogleCodeExporter commented 9 years ago
Here'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()
}}}

Original comment by kon...@gmail.com on 12 Jun 2010 at 11:27

GoogleCodeExporter commented 9 years ago
I'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:
    ...
}}}

Original comment by fuzzyman on 12 Jun 2010 at 1:16

GoogleCodeExporter commented 9 years ago
> I'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()?

Original comment by kon...@gmail.com on 12 Jun 2010 at 1:53

GoogleCodeExporter commented 9 years ago
I 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.

Original comment by fuzzyman on 12 Jun 2010 at 2:45

GoogleCodeExporter commented 9 years ago

Original comment by fuzzyman on 13 Jun 2010 at 8:43

GoogleCodeExporter commented 9 years ago
Actually unpatch and teardown are both fine as names.

Original comment by fuzzyman on 15 Oct 2010 at 4:28

GoogleCodeExporter commented 9 years ago
I 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"]

Original comment by fschulz...@googlemail.com on 15 Oct 2010 at 4:33

GoogleCodeExporter commented 9 years ago
A 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()
}}}

Original comment by fuzzyman on 12 Nov 2010 at 12:52

GoogleCodeExporter commented 9 years ago
My 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? 

Original comment by fuzzyman on 12 Nov 2010 at 1:20

GoogleCodeExporter commented 9 years ago
Note 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.

Original comment by fuzzyman on 12 Nov 2010 at 2:07

GoogleCodeExporter commented 9 years ago
Note 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.

Original comment by fuzzyman on 6 Dec 2010 at 11:17

GoogleCodeExporter commented 9 years ago

Original comment by fuzzyman on 28 May 2011 at 11:24

GoogleCodeExporter commented 9 years ago
I'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.

Original comment by wolfgang.schnerring on 30 Nov 2011 at 5:01

GoogleCodeExporter commented 9 years ago
I 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?

Original comment by florian....@gmx.net on 9 Dec 2011 at 11:17

GoogleCodeExporter commented 9 years ago
I agree with florian that *some* way of accessing the mocks after creation 
would be useful.

Original comment by fuzzyman on 29 Dec 2011 at 12:50

GoogleCodeExporter commented 9 years ago
patcher.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?

Original comment by fuzzyman on 14 Nov 2013 at 11:15