homepage

This issue tracker has been migrated to GitHub , and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Add to unittest.TestCase support for using context managers
Type: enhancement Stage:
Components: Library (Lib) Versions: Python 3.4
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: michael.foord Nosy List: Julian, cbc, chris.jerdonek, eli.bendersky, eric.araujo, martin.panter, michael.foord, r.david.murray, serhiy.storchaka
Priority: normal Keywords: patch

Created on 2012年07月14日 15:33 by chris.jerdonek, last changed 2022年04月11日 14:57 by admin.

Files
File name Uploaded Description Edit
issue-15351-concept.patch chris.jerdonek, 2012年07月16日 20:53 review
Messages (9)
msg165454 - (view) Author: Chris Jerdonek (chris.jerdonek) * (Python committer) Date: 2012年07月14日 15:33
The setUp() and tearDown() methods of unittest.TestCase are of course extremely useful. But sometimes one has set up and tear down functionality that one would like to apply in the form of an existing context manager (and that may be from an outside source).
There is currently no clear or clean way to do this. It would be nice if unittest exposed a way to do this.
The closest I have been able to come is overriding TestCase.run() as follows:
class MyTest(unittest.TestCase):
 def run(self, result=None):
 with my_context_manager() as foo:
 # Do stuff.
 super(MyTest, self).run(result)
But this is not ideal because the context manager is surrounding more than it should (various test initialization code internal to unittest, etc). Also, ideally the API would let one apply a context manager either before or after setUp() and tearDown(), or both.
Here is one idea for an API. unittest.TestCase could expose a setUpContext() context manager that wraps the user-defined setUp() and tearDown(), and also a runTestMethod() method that runs the test method code by itself (i.e. currently the following line of unittest/case.py: `self._executeTestPart(testMethod, outcome, isTest=True)`).
To use the API, the user could override a simple method called something like runTest():
 def runTest(self):
 with setUpContext():
 self.runTestMethod()
The user would, in the override, be free to insert additional context managers before or after setUpContext(), or both.
msg165466 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2012年07月14日 20:05
Well, if you want to invoke the context in setup/teardown for some reason (as opposed to in the test methods themselves), you can do this:
 def setUp(self):
 self.foo = MyContextManager.__enter__()
 self.addCleanup(MyContextManager.__exit__())
Personally I rarely do this (except occasionally the mock equivalent, see below), preferring to call the context manager explicitly in the test method itself, often factored out into a test helper.
I think we as a community are still learning how best to use context managers and what the optimum design of context manager is. There is some thought that a context manager should always provide a non-context way of getting at the functionality of the enter and exit methods. For example, the mock context managers have start() and stop() methods. There has also been a small amount of discussion of making more use of context managers in unittest itself, possibly along the lines you suggest.
I think this may be an area in which we are not yet ready to settle on an API. Michael may have a different opinion, of course ;)
msg165467 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2012年07月14日 20:08
That should have been
 self.addCleanup(MyContextManager.__exit__)
You could alternatively call __exit__() explicitly in tearDown, of course, but I believe addCleanup is a more reliable cleanup than tearDown.
msg165470 - (view) Author: Chris Jerdonek (chris.jerdonek) * (Python committer) Date: 2012年07月14日 20:51
Thanks for the interesting background and feedback. I was aware of the __enter__/__exit__ option but not the other information. And yes, I agree on the importance of trying and discussing any API before settling on it. The one I suggested was merely a point of departure. :)
msg165534 - (view) Author: Michael Foord (michael.foord) * (Python committer) Date: 2012年07月15日 16:12
A method on TestCase that *just* executes the test method - allowing for overriding in subclasses - is an interesting idea. Including setUp and tearDown would be harder because TestCase necessarily does a bunch of bookkeeping between each of these steps.
msg165655 - (view) Author: Chris Jerdonek (chris.jerdonek) * (Python committer) Date: 2012年07月16日 20:53
Attached is a patch illustrating the API I suggested for discussion.
To add custom setup and teardown context managers, the user can override the following method:
 def executeTest(self):
 with self.setUpContext():
 self.runTestMethod()
The custom context managers can be placed either before or after the existing setUp/tearDown, or both.
The patch preserves the existing behavior that tearDown() should run only if setUp() was successful, and that doCleanups() should always run. All tests continue to pass with the patch.
msg168963 - (view) Author: Chris Jerdonek (chris.jerdonek) * (Python committer) Date: 2012年08月23日 20:02
Adding Éric because of the interest in test setup and tear down in issue 11664.
msg186172 - (view) Author: Julian Berman (Julian) * Date: 2013年04月07日 01:25
Now that we have contextlib.ExitStack, I think we should consider that here.
I.e., I think ExitStack deserves a method that calls its __enter__ and __exit__, say .enter() and .exit(), and then the idiom for this wouldn't require anything on TestCase, it'd be:
class TestStuff(TestCase):
 def setUp(self):
 self.stack = ExitStack()
 self.stack.enter_context(my_context_manager())
 self.stack.enter_context(my_context_manager2())
 self.stack.enter_context(my_context_manager3())
 self.stack.enter()
 self.addCleanup(self.stack.exit)
msg400553 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2021年08月29日 17:02
Opened issue45046 for completely different approach to this problem.
History
Date User Action Args
2022年04月11日 14:57:32adminsetgithub: 59556
2021年08月29日 17:02:58serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg400553
2014年03月20日 23:58:35martin.pantersetnosy: + martin.panter
2013年04月07日 01:25:12Juliansetnosy: + Julian
messages: + msg186172
2013年04月02日 22:58:22cbcsetnosy: + cbc
2013年02月11日 21:04:28michael.foordsetassignee: michael.foord
2012年10月15日 13:06:00eli.benderskysetnosy: + eli.bendersky
2012年08月23日 20:02:44chris.jerdoneksetnosy: + eric.araujo
messages: + msg168963
2012年07月16日 20:53:25chris.jerdoneksetfiles: + issue-15351-concept.patch
keywords: + patch
messages: + msg165655
2012年07月15日 16:12:08michael.foordsetmessages: + msg165534
2012年07月14日 20:51:54chris.jerdoneksetmessages: + msg165470
2012年07月14日 20:08:22r.david.murraysetmessages: + msg165467
2012年07月14日 20:05:55r.david.murraysetnosy: + r.david.murray, michael.foord

messages: + msg165466
versions: + Python 3.4
2012年07月14日 15:33:51chris.jerdonekcreate

AltStyle によって変換されたページ (->オリジナル) /