Hi Florian, On Fri, Aug 20, 2010 at 15:49 +0200, Florian Bauer wrote: > Hi all, > > I'm trying to make an existing testsuite py.test compatible. > At the moment, we use nose as test runner. I stumbled upon the following > (simplified example). > > from functools import partial > > def forall_cases(cases): > def decorate(testfn): > def gen(): > for case in cases: > description = case[0] > args = case[1:] > func = partial(testfn, *args) > func.description = description > yield func, > gen.__name__= 'test_%s_' % testfn.__name__ > # > # inject the generator into the module testfn came from > # > gen.__module__ = testfn.__module__ > return gen > return decorate > > > @forall_cases([['case1', 1, 1], ['case2', 2, 2],['case3', 3, 4]]) def > test_equal(a, b): > assert a == b
Hum, is it an option to rather use a different decorator that makes use of py.test's more general parametrized testing feature? See here: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/ for some general examples. In your case you would need to 1) define @forallcases as a simple marker, e.g.: forallcases = py.test.mark.forallcases 2) implement a pytest_generate_tests hooks that checks for the "forallcases" decorator and generates the test function invocations. The second part can just live in a conftest.py file and does not conflict with the nose-way of running tests. For the first you could try to just do something like def pytest_configure(config): import module_that_contains_forallcases module_that_contains_forallcases.forallcases = py.test.mark.forallcases If the latter lives in a conftest.py file at the root of your project or at the root of all test modules it should be executed before any test module is imported (which might import and use the forallcases decorator). > If I run this with nosetests, I get 3 test cases, 2 pass and 1 fail. > > py.test tries to call inspect.getsource on the partial object, which > results in a TypeError: > > $ py.test -v > ... > INTERNALERROR> > INTERNALERROR> object = <functools.partial object at 0x00F019C0> > INTERNALERROR> > INTERNALERROR> def getfile(object): > INTERNALERROR> """Work out which source or compiled file an > INTERNALERROR> object was d > efined in.""" Can you post or attach a full traceback? I agree that a) it would be nice if nose and py.test would be more compatible here b) the error is obscure. OTOH i consider yield-based parametrization as a kind of dead-end. It certainly causes a more complex implementation for the testing machinery and can not provide features/reporting as cleanly as the above mentioned parametrized testing. > ... > INTERNALERROR> > raise TypeError('arg is not a module, class, > method, ' > INTERNALERROR> 'function, traceback, frame, or > INTERNALERROR> code obje > ct') > INTERNALERROR> E TypeError: arg is not a module, class, method, > function, > traceback, frame, or code object > INTERNALERROR> > INTERNALERROR> object = <functools.partial object at 0x00F019C0> > INTERNALERROR> > INTERNALERROR> c:\Python26\lib\inspect.py:418: TypeError > > This seems to be a documented limitation of inspect.getsource > (functools.partial returns a partial object, not a function). > I can fix this by replacing functools.partial with code given as roughly > equivalent in the python documentation: > > def partial(func, *args, **keywords): > def newfunc(*fargs, **fkeywords): > newkeywords = keywords.copy() > newkeywords.update(fkeywords) > return func(*(args + fargs), **newkeywords) > newfunc.func = func > newfunc.args = args > newfunc.keywords = keywords > return newfunc > > But I was certainly not expecting this. The default behavior of py.test > is even more puzzling, as it fails silently: > > fba...@mn-eng-lt-fb ~/My Documents/Software/pytestbug1 $ py.test > ============================= test session starts > ============================= platform win32 -- Python 2.6.5 -- > pytest-1.3.3 test path 1: c:\docume~1\fbauer\My > Documents\Software\pytestbug1 > > test_case.py .. > > In my actual code, the forall_cases decorator lives in a utils module. > Is there a conditional flag that can tell me whether I'm running under > py.test? Then I could start experimenting with parametric tests using > funcargs, while keeping the test suite runnable with nose at the moment. > I still have a bug in the test suite, as I have tests passing under nose > that fail under py.test... There is no official way to detect if code is running within a test session. You might do something like: # contents of conftest.py def pytest_configure(config): import some_app_module some_app_module._testing = True and then do a "hasattr(some_app_module, '_testing')" check or so. However, most people don't consider it good practise to have application level code become aware if it's being tested or not. Instead people use monkeypatching or dependency-injection to modify app behaviour. HTH, holger _______________________________________________ py-dev mailing list py-dev@codespeak.net http://codespeak.net/mailman/listinfo/py-dev