[svn r63805] first step towards having a dedicated test-run plugin, some more basics missing
--HG-- branch : trunk
This commit is contained in:
		
							parent
							
								
									bba69f207b
								
							
						
					
					
						commit
						9aed6ddcd0
					
				|  | @ -0,0 +1,273 @@ | |||
| import py | ||||
| 
 | ||||
| class RunnerPlugin: | ||||
|     def pytest_configure(self, config): | ||||
|         config._setupstate = SetupState() | ||||
| 
 | ||||
|     def pytest_unconfigure(self, config): | ||||
|         config._setupstate.teardown_all() | ||||
| 
 | ||||
|     def pytest_item_setup_and_runtest(self, item): | ||||
|         setupstate = item.config._setupstate | ||||
|         call = item.config.guardedcall(lambda: setupstate.prepare(item)) | ||||
|         rep = ItemSetupReport(item, call.excinfo, call.outerr) | ||||
|         if call.excinfo: | ||||
|             item.config.pytestplugins.notify("itemsetupreport", rep) | ||||
|         else: | ||||
|             call = item.config.guardedcall(lambda: item.runtest()) | ||||
|             item.config.mc.pytest_item_runtest_finished( | ||||
|                 item=item, excinfo=call.excinfo, outerr=call.outerr) | ||||
|             call = item.config.guardedcall(lambda: self.teardown_exact(item)) | ||||
|             if call.excinfo: | ||||
|                 rep = ItemSetupReport(item, call.excinfo, call.outerr) | ||||
|                 item.config.pytestplugins.notify("itemsetupreport", rep) | ||||
| 
 | ||||
|     def pytest_collector_collect(self, collector): | ||||
|         call = item.config.guardedcall(lambda x: collector._memocollect()) | ||||
|         return CollectReport(collector, res, excinfo, outerr) | ||||
| 
 | ||||
| class BaseReport(object): | ||||
|     def __repr__(self): | ||||
|         l = ["%s=%s" %(key, value) | ||||
|            for key, value in self.__dict__.items()] | ||||
|         return "<%s %s>" %(self.__class__.__name__, " ".join(l),) | ||||
| 
 | ||||
|     def toterminal(self, out): | ||||
|         longrepr = self.longrepr  | ||||
|         if hasattr(longrepr, 'toterminal'): | ||||
|             longrepr.toterminal(out) | ||||
|         else: | ||||
|             out.line(str(longrepr)) | ||||
|     | ||||
| class ItemTestReport(BaseReport): | ||||
|     failed = passed = skipped = False | ||||
| 
 | ||||
|     def __init__(self, colitem, excinfo=None, when=None, outerr=None): | ||||
|         self.colitem = colitem  | ||||
|         if colitem and when != "setup": | ||||
|             self.keywords = colitem.readkeywords()  | ||||
|         else: | ||||
|             # if we fail during setup it might mean  | ||||
|             # we are not able to access the underlying object | ||||
|             # this might e.g. happen if we are unpickled  | ||||
|             # and our parent collector did not collect us  | ||||
|             # (because it e.g. skipped for platform reasons) | ||||
|             self.keywords = {}   | ||||
|         if not excinfo: | ||||
|             self.passed = True | ||||
|             self.shortrepr = "."  | ||||
|         else: | ||||
|             self.when = when  | ||||
|             if not isinstance(excinfo, py.code.ExceptionInfo): | ||||
|                 self.failed = True | ||||
|                 shortrepr = "?" | ||||
|                 longrepr = excinfo  | ||||
|             elif excinfo.errisinstance(Skipped): | ||||
|                 self.skipped = True  | ||||
|                 shortrepr = "s" | ||||
|                 longrepr = self.colitem._repr_failure_py(excinfo, outerr) | ||||
|             else: | ||||
|                 self.failed = True | ||||
|                 shortrepr = self.colitem.shortfailurerepr | ||||
|                 if self.when == "execute": | ||||
|                     longrepr = self.colitem.repr_failure(excinfo, outerr) | ||||
|                 else: # exception in setup or teardown  | ||||
|                     longrepr = self.colitem._repr_failure_py(excinfo, outerr) | ||||
|                     shortrepr = shortrepr.lower() | ||||
|             self.shortrepr = shortrepr  | ||||
|             self.longrepr = longrepr  | ||||
|              | ||||
| 
 | ||||
| class CollectReport(BaseReport): | ||||
|     skipped = failed = passed = False  | ||||
| 
 | ||||
|     def __init__(self, colitem, result, excinfo=None, outerr=None): | ||||
|         # XXX rename to collector  | ||||
|         self.colitem = colitem  | ||||
|         if not excinfo: | ||||
|             self.passed = True | ||||
|             self.result = result  | ||||
|         else: | ||||
|             self.outerr = outerr | ||||
|             self.longrepr = self.colitem._repr_failure_py(excinfo, outerr) | ||||
|             if excinfo.errisinstance(Skipped): | ||||
|                 self.skipped = True | ||||
|                 self.reason = str(excinfo.value) | ||||
|             else: | ||||
|                 self.failed = True | ||||
| 
 | ||||
| class ItemSetupReport(BaseReport): | ||||
|     failed = passed = skipped = False | ||||
|     def __init__(self, item, excinfo=None, outerr=None): | ||||
|         self.item = item  | ||||
|         self.outerr = outerr  | ||||
|         if not excinfo: | ||||
|             self.passed = True | ||||
|         else: | ||||
|             if excinfo.errisinstance(Skipped): | ||||
|                 self.skipped = True  | ||||
|             else: | ||||
|                 self.failed = True | ||||
|             self.excrepr = item._repr_failure_py(excinfo, []) | ||||
| 
 | ||||
| class SetupState(object): | ||||
|     """ shared state for setting up/tearing down test items or collectors. """ | ||||
|     def __init__(self): | ||||
|         self.stack = [] | ||||
| 
 | ||||
|     def teardown_all(self):  | ||||
|         while self.stack:  | ||||
|             col = self.stack.pop()  | ||||
|             col.teardown()  | ||||
| 
 | ||||
|     def teardown_exact(self, item): | ||||
|         if self.stack and self.stack[-1] == item: | ||||
|             col = self.stack.pop() | ||||
|             col.teardown() | ||||
|       | ||||
|     def prepare(self, colitem):  | ||||
|         """ setup objects along the collector chain to the test-method | ||||
|             Teardown any unneccessary previously setup objects.""" | ||||
|         needed_collectors = colitem.listchain()  | ||||
|         while self.stack:  | ||||
|             if self.stack == needed_collectors[:len(self.stack)]:  | ||||
|                 break  | ||||
|             col = self.stack.pop()  | ||||
|             col.teardown() | ||||
|         for col in needed_collectors[len(self.stack):]:  | ||||
|             col.setup()  | ||||
|             self.stack.append(col)  | ||||
| 
 | ||||
| # =============================================================================== | ||||
| # | ||||
| # plugin tests  | ||||
| # | ||||
| # =============================================================================== | ||||
| 
 | ||||
| def test_generic(plugintester): | ||||
|     plugintester.apicheck(RunnerPlugin()) | ||||
| 
 | ||||
| class TestSetupState: | ||||
|     def test_setup_prepare(self, testdir): | ||||
|         modcol = testdir.getmodulecol(""" | ||||
|             def setup_function(function): | ||||
|                 function.myfunc = function | ||||
|             def test_func1(): | ||||
|                 pass | ||||
|             def test_func2(): | ||||
|                 pass | ||||
|             def teardown_function(function): | ||||
|                 del function.myfunc  | ||||
|         """) | ||||
|         item1, item2 = modcol.collect() | ||||
|         setup = SetupState() | ||||
|         setup.prepare(item1) | ||||
|         assert item1.obj.myfunc == item1.obj  | ||||
|         assert not hasattr(item2, 'myfunc') | ||||
| 
 | ||||
|         setup.prepare(item2) | ||||
|         assert item2.obj.myfunc == item2.obj  | ||||
|         assert not hasattr(item1, 'myfunc') | ||||
| 
 | ||||
|     def test_setup_teardown_exact(self, testdir): | ||||
|         item = testdir.getitem(""" | ||||
|             def test_func(): | ||||
|                 pass | ||||
|             def teardown_function(function): | ||||
|                 function.tear = "down" | ||||
|         """) | ||||
|         setup = SetupState() | ||||
|         setup.prepare(item) | ||||
|         setup.teardown_exact(item) | ||||
|         assert item.obj.tear == "down" | ||||
| 
 | ||||
|     def test_setup_teardown_exact(self, testdir): | ||||
|         item = testdir.getitem(""" | ||||
|             def setup_module(mod): | ||||
|                 mod.x = 1 | ||||
|             def setup_function(function): | ||||
|                 function.y = 2 | ||||
|             def test_func(): | ||||
|                 pass | ||||
|             def teardown_function(function): | ||||
|                 del function.y | ||||
|             def teardown_module(mod): | ||||
|                 del mod.x | ||||
|         """) | ||||
|         setup = SetupState() | ||||
|         setup.prepare(item) | ||||
|         assert item.obj.y == 2 | ||||
|         assert item.parent.obj.x == 1 | ||||
|         setup.teardown_all() | ||||
|         assert not hasattr(item.obj, 'y') | ||||
|         assert not hasattr(item.parent.obj, 'x') | ||||
| 
 | ||||
| class TestRunnerPlugin: | ||||
|     disabled = True | ||||
|     def test_pytest_item_setup_and_runtest(self, testdir): | ||||
|         item = testdir.getitem("""def test_func(): pass""") | ||||
|         plugin = RunnerPlugin() | ||||
|         plugin.pytest_configure(item.config) | ||||
|         sorter = testdir.geteventrecorder(item.config) | ||||
|         plugin.pytest_item_setup_and_runtest(item) | ||||
|         rep = sorter.getreport("itemtestreport") | ||||
|         assert rep.passed  | ||||
|          | ||||
|          | ||||
| class TestSetupEvents: | ||||
|     disabled = True | ||||
| 
 | ||||
|     def test_setup_runtest_ok(self, testdir): | ||||
|         sorter = testdir.inline_runsource(""" | ||||
|             def setup_module(mod): | ||||
|                 pass  | ||||
|             def test_func(): | ||||
|                 pass | ||||
|         """) | ||||
|         assert not sorter.getcalls("itemsetupreport") | ||||
| 
 | ||||
|     def test_setup_fails(self, testdir): | ||||
|         sorter = testdir.inline_runsource(""" | ||||
|             def setup_module(mod): | ||||
|                 print "world" | ||||
|                 raise ValueError(42) | ||||
|             def test_func(): | ||||
|                 pass | ||||
|         """) | ||||
|         rep = sorter.popcall("itemsetupreport").rep | ||||
|         assert rep.failed | ||||
|         assert not rep.skipped | ||||
|         assert rep.excrepr  | ||||
|         assert "42" in str(rep.excrepr) | ||||
|         assert rep.outerr[0].find("world") != -1 | ||||
| 
 | ||||
|     def test_teardown_fails(self, testdir): | ||||
|         sorter = testdir.inline_runsource(""" | ||||
|             def test_func(): | ||||
|                 pass | ||||
|             def teardown_function(func):  | ||||
|                 print "13" | ||||
|                 raise ValueError(25) | ||||
|         """) | ||||
|         rep = evrec.popcall("itemsetupreport").rep  | ||||
|         assert rep.failed  | ||||
|         assert rep.item == item  | ||||
|         assert not rep.passed | ||||
|         assert "13" in rep.outerr[0] | ||||
|         assert "25" in str(rep.excrepr) | ||||
| 
 | ||||
|     def test_setup_skips(self, testdir): | ||||
|         sorter = testdir.inline_runsource(""" | ||||
|             import py | ||||
|             def setup_module(mod): | ||||
|                 py.test.skip("17") | ||||
|             def test_func(): | ||||
|                 pass | ||||
|         """) | ||||
|         rep = sorter.popcall("itemsetupreport") | ||||
|         assert not rep.failed | ||||
|         assert rep.skipped | ||||
|         assert rep.excrepr  | ||||
|         assert "17" in str(rep.excrepr) | ||||
|      | ||||
| 
 | ||||
|  | @ -196,24 +196,3 @@ class SetupState(object): | |||
|         for col in needed_collectors[len(self.stack):]:  | ||||
|             col.setup()  | ||||
|             self.stack.append(col)  | ||||
| 
 | ||||
|     def do_setup(self, item): | ||||
|         call = item.config.guardedcall(lambda: self.prepare(item)) | ||||
|         rep = ItemSetupReport(item, call.excinfo, call.outerr) | ||||
|         item.config.pytestplugins.notify("itemsetupreport", rep) | ||||
|         return not call.excinfo  | ||||
| 
 | ||||
|     def do_teardown(self, item): | ||||
|         call = item.config.guardedcall(lambda: self.teardown_exact(item)) | ||||
|         if call.excinfo: | ||||
|             rep = ItemSetupReport(item, call.excinfo, call.outerr) | ||||
|             item.config.pytestplugins.notify("itemsetupreport", rep) | ||||
| 
 | ||||
|     def do_fixture_and_runtest(self, item): | ||||
|         """ setup fixture and perform actual item.runtest(). """ | ||||
|         if self.do_setup(item): | ||||
|             call = item.config.guardedcall(lambda: item.runtest()) | ||||
|             item.config.pytestplugins.notify( | ||||
|                 "item_runtest_finished",  | ||||
|                 item=item, excinfo=call.excinfo, outerr=call.outerr) | ||||
|             self.do_teardown(item) | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| from py.__.test.config import SetupState | ||||
| 
 | ||||
| class TestSetupState: | ||||
|     disabled = True | ||||
|     def test_setup_ok(self, testdir): | ||||
|         item = testdir.getitem(""" | ||||
|             def setup_module(mod): | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue