[py-svn] r63628 - in py/trunk/py/test: . plugin testing

hpk at codespeak.net hpk at codespeak.net
Sat Apr 4 21:06:23 CEST 2009


Author: hpk
Date: Sat Apr  4 21:06:20 2009
New Revision: 63628

Added:
   py/trunk/py/test/testing/test_fixture_and_setup.py
      - copied, changed from r63589, py/trunk/py/test/testing/test_setup_nested.py
Removed:
   py/trunk/py/test/testing/test_setup_nested.py
Modified:
   py/trunk/py/test/config.py
   py/trunk/py/test/plugin/api.py
   py/trunk/py/test/plugin/pytest_pytester.py
   py/trunk/py/test/runner.py
Log:
* shuffle SetupState and fixture handling into runner.py 
* introduce a itemsetupreport and new setupitem/teardownitem methods. 
* more tests



Modified: py/trunk/py/test/config.py
==============================================================================
--- py/trunk/py/test/config.py	(original)
+++ py/trunk/py/test/config.py	Sat Apr  4 21:06:20 2009
@@ -3,6 +3,7 @@
 
 from py.__.test import parseopt
 from py.__.misc.warn import APIWARN
+from py.__.test.runner import SetupState
 
 def ensuretemp(string, dir=1): 
     """ return temporary directory path with
@@ -312,34 +313,6 @@
     else:
         return pkgdir.dirpath()
 
-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) 
 
 # this is the one per-process instance of py.test configuration 
 config_per_process = Config(

Modified: py/trunk/py/test/plugin/api.py
==============================================================================
--- py/trunk/py/test/plugin/api.py	(original)
+++ py/trunk/py/test/plugin/api.py	Sat Apr  4 21:06:20 2009
@@ -85,6 +85,9 @@
     def pyevent__itemtestreport(self, event):
         """ test has been run. """
 
+    def pyevent__itemsetupreport(self, rep):
+        """ test has been run. """
+
     def pyevent__deselected(self, items):
         """ collected items that were deselected (by keyword). """
 

Modified: py/trunk/py/test/plugin/pytest_pytester.py
==============================================================================
--- py/trunk/py/test/plugin/pytest_pytester.py	(original)
+++ py/trunk/py/test/plugin/pytest_pytester.py	Sat Apr  4 21:06:20 2009
@@ -74,6 +74,11 @@
         if hasattr(self, '_olddir'):
             self._olddir.chdir()
 
+    def geteventrecorder(self, config):
+        evrec = EventRecorder(config.bus) 
+        self.pyfuncitem.addfinalizer(lambda: config.bus.unregister(evrec))
+        return evrec
+
     def chdir(self):
         old = self.tmpdir.chdir()
         if not hasattr(self, '_olddir'):
@@ -174,9 +179,12 @@
 
     def getitem(self,  source, funcname="test_func"):
         modcol = self.getmodulecol(source)
-        item = modcol.join(funcname) 
-        assert item is not None, "%r item not found in module:\n%s" %(funcname, source)
-        return item 
+        moditems = modcol.collect()
+        for item in modcol.collect():
+            if item.name == funcname:
+                return item 
+        else:
+            assert 0, "%r item not found in module:\n%s" %(funcname, source)
 
     def getitems(self,  source):
         modcol = self.getmodulecol(source)
@@ -284,12 +292,13 @@
         for i, event in py.builtin.enumerate(self.events):
             if event.name == name:
                 del self.events[i]
-                return event
+                eventparser = self.geteventparser(name)
+                return eventparser(*event.args, **event.kwargs)
         raise KeyError("popevent: %r not found in %r"  %(name, self.events))
 
     def getevents(self, eventname):
         """ return list of ParsedEvent instances matching the given eventname. """
-        method = self.geteventmethod(eventname)
+        method = self.geteventparser(eventname)
         l = []
         for event in self.events:
             if event.name == eventname:
@@ -297,23 +306,18 @@
                 l.append(pevent)  
         return l
 
-    def geteventmethod(self, eventname):
+    def geteventparser(self, eventname):
         mname = "pyevent__" + eventname
         method = getattr(api.Events, mname)
         args, varargs, varkw, default = inspect.getargspec(method)
         assert args[0] == "self"
         args = args[1:]
         fspec = inspect.formatargspec(args, varargs, varkw, default)
-        source = """def %(mname)s%(fspec)s: 
-                    return ParsedEvent(locals())""" % locals()
-        print source
-        exec source
+        code = py.code.compile("""def %(mname)s%(fspec)s: 
+                    return ParsedEvent(locals())""" % locals())
+        exec code
         return locals()[mname]
 
-
-    def firstparsedevent(self, eventname):
-        return  self.parsedevents(eventname)[0]
-
     def get(self, cls):
         l = []
         for event in self.events:

Modified: py/trunk/py/test/runner.py
==============================================================================
--- py/trunk/py/test/runner.py	(original)
+++ py/trunk/py/test/runner.py	Sat Apr  4 21:06:20 2009
@@ -6,7 +6,7 @@
     * and generating report events about it 
 """
 
-import py, os, sys
+import py
 
 from py.__.test.outcome import Exit, Skipped
 
@@ -55,7 +55,6 @@
     return CollectionReport(collector, res, excinfo, outerr)
 
 from cPickle import Pickler, Unpickler
-from cStringIO import StringIO
 
 def forked_run_report(item, pdb=None):
     EXITSTATUS_TESTEXIT = 4
@@ -66,7 +65,7 @@
         try:
             testrep = basic_run_report(item)
         except (KeyboardInterrupt, Exit): 
-            os._exit(EXITSTATUS_TESTEXIT)
+            py.std.os._exit(EXITSTATUS_TESTEXIT)
         return ipickle.dumps(testrep)
 
     ff = py.process.ForkedFunc(runforked)
@@ -164,3 +163,70 @@
         else:
             out.line(str(longrepr))
 
+class ItemSetupReport(BaseReport):
+    """ Test Execution Report. """
+    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, outerr)
+
+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) 
+
+    def fixturecall(self, callable, item):
+        excinfo = None
+        capture = item.config._getcapture()
+        try:
+            try:
+                callable(item)
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except:
+                excinfo = py.code.ExceptionInfo()
+        finally:
+            outerr = capture.reset()
+        if not excinfo:
+            return True
+        else:
+            rep = ItemSetupReport(item, excinfo, outerr)
+            item.config.pytestplugins.notify("itemsetupreport", rep)
+
+    def setupitem(self, item):
+        return self.fixturecall(self.prepare, item) 
+
+    def teardownitem(self, item):
+        self.fixturecall(self.teardown_exact, item) 

Copied: py/trunk/py/test/testing/test_fixture_and_setup.py (from r63589, py/trunk/py/test/testing/test_setup_nested.py)
==============================================================================
--- py/trunk/py/test/testing/test_setup_nested.py	(original)
+++ py/trunk/py/test/testing/test_fixture_and_setup.py	Sat Apr  4 21:06:20 2009
@@ -138,3 +138,74 @@
                 assert not hasattr(self, 'world')
     """)
     sorter.assertoutcome(passed=4, failed=0)
+
+from py.__.test.config import SetupState
+
+class TestSetupState:
+    def test_setupitem_works(self, testdir):
+        item = testdir.getitem("""
+            def setup_module(mod):
+                pass 
+            def test_func():
+                pass
+        """)
+        evrec = testdir.geteventrecorder(item.config)
+        setup = SetupState()
+        res = setup.setupitem(item)
+        assert res
+
+    def test_setupitem_fails(self, testdir):
+        item = testdir.getitem("""
+            def setup_module(mod):
+                print "world"
+                raise ValueError(42)
+            def test_func():
+                pass
+        """)
+        evrec = testdir.geteventrecorder(item.config)
+        setup = SetupState()
+        res = setup.setupitem(item)
+        assert not res
+        rep = evrec.popevent("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_teardownitem_fails(self, testdir):
+        item = testdir.getitem("""
+            def test_func():
+                pass
+            def teardown_function(func): 
+                print "13"
+                raise ValueError(25)
+        """)
+        evrec = testdir.geteventrecorder(item.config)
+        setup = SetupState()
+        res = setup.setupitem(item)
+        assert res 
+        setup.teardownitem(item)
+        rep = evrec.popevent("itemsetupreport").rep
+        assert rep.item == item 
+        assert rep.failed 
+        assert not rep.passed
+        assert "13" in rep.outerr[0]
+        assert "25" in str(rep.excrepr)
+
+    def test_setupitem_skips(self, testdir):
+        item = testdir.getitem("""
+            import py
+            def setup_module(mod):
+                py.test.skip("17")
+            def test_func():
+                pass
+        """)
+        evrec = testdir.geteventrecorder(item.config)
+        setup = SetupState()
+        setup.setupitem(item)
+        rep = evrec.popevent("itemsetupreport").rep
+        assert not rep.failed
+        assert rep.skipped
+        assert rep.excrepr 
+        assert "17" in str(rep.excrepr)

Deleted: /py/trunk/py/test/testing/test_setup_nested.py
==============================================================================
--- /py/trunk/py/test/testing/test_setup_nested.py	Sat Apr  4 21:06:20 2009
+++ (empty file)
@@ -1,140 +0,0 @@
-#
-# test correct setup/teardowns at
-# module, class, and instance level
-
-def test_module_and_function_setup(testdir):
-    sorter = testdir.inline_runsource(""" 
-        modlevel = []
-        def setup_module(module):
-            assert not modlevel
-            module.modlevel.append(42)
-
-        def teardown_module(module):
-            modlevel.pop()
-
-        def setup_function(function):
-            function.answer = 17
-
-        def teardown_function(function):
-            del function.answer
-
-        def test_modlevel():
-            assert modlevel[0] == 42
-            assert test_modlevel.answer == 17
-
-        class TestFromClass: 
-            def test_module(self):
-                assert modlevel[0] == 42
-                assert not hasattr(test_modlevel, 'answer') 
-    """)
-    rep = sorter.getreport("test_modlevel") 
-    assert rep.passed 
-    rep = sorter.getreport("test_module") 
-    assert rep.passed 
-
-def test_class_setup(testdir):
-    sorter = testdir.inline_runsource("""
-        class TestSimpleClassSetup:
-            clslevel = []
-            def setup_class(cls):
-                cls.clslevel.append(23)
-
-            def teardown_class(cls):
-                cls.clslevel.pop()
-
-            def test_classlevel(self):
-                assert self.clslevel[0] == 23
-
-        class TestInheritedClassSetupStillWorks(TestSimpleClassSetup):
-            def test_classlevel_anothertime(self):
-                assert self.clslevel == [23]
-
-        def test_cleanup():
-            assert not TestSimpleClassSetup.clslevel 
-            assert not TestInheritedClassSetupStillWorks.clslevel
-    """)
-    sorter.assertoutcome(passed=1+2+1)
-
-def test_method_setup(testdir):
-    sorter = testdir.inline_runsource("""
-        class TestSetupMethod:
-            def setup_method(self, meth):
-                self.methsetup = meth 
-            def teardown_method(self, meth):
-                del self.methsetup 
-
-            def test_some(self):
-                assert self.methsetup == self.test_some 
-
-            def test_other(self):
-                assert self.methsetup == self.test_other
-    """)
-    sorter.assertoutcome(passed=2)
-       
-def test_method_generator_setup(testdir):
-    sorter = testdir.inline_runsource("""
-        class TestSetupTeardownOnInstance: 
-            def setup_class(cls):
-                cls.classsetup = True 
-
-            def setup_method(self, method):
-                self.methsetup = method 
-
-            def test_generate(self):
-                assert self.classsetup 
-                assert self.methsetup == self.test_generate 
-                yield self.generated, 5
-                yield self.generated, 2
-
-            def generated(self, value):
-                assert self.classsetup 
-                assert self.methsetup == self.test_generate 
-                assert value == 5
-    """)
-    sorter.assertoutcome(passed=1, failed=1)
-
-def test_func_generator_setup(testdir):
-    sorter = testdir.inline_runsource(""" 
-        import sys
-
-        def setup_module(mod):
-            print "setup_module"
-            mod.x = []
-        
-        def setup_function(fun):
-            print "setup_function"
-            x.append(1)
-
-        def teardown_function(fun):
-            print "teardown_function" 
-            x.pop()
-        
-        def test_one():
-            assert x == [1]
-            def check():
-                print "check" 
-                print >>sys.stderr, "e" 
-                assert x == [1]
-            yield check 
-            assert x == [1]
-    """)
-    rep = sorter.getreport("test_one") 
-    assert rep.passed 
-        
-def test_method_setup_uses_fresh_instances(testdir):
-    sorter = testdir.inline_runsource("""
-        class TestSelfState1: 
-            def __init__(self):
-                self.hello = 42
-            def test_hello(self):
-                self.world = 23
-            def test_afterhello(self):
-                assert not hasattr(self, 'world')
-                assert self.hello == 42
-        class TestSelfState2: 
-            def test_hello(self):
-                self.world = 10
-            def test_world(self):
-                assert not hasattr(self, 'world')
-    """)
-    sorter.assertoutcome(passed=4, failed=0)



More information about the pytest-commit mailing list