[py-dev] RFC: draft new resource management API (v1)

holger krekel holger at merlinux.eu
Thu Jun 28 10:15:45 CEST 2012


On Thu, Jun 28, 2012 at 08:47 +0100, Floris Bruynooghe wrote:
> On 27 June 2012 19:36, holger krekel <holger at merlinux.eu> wrote:
> > On Wed, Jun 27, 2012 at 16:59 +0100, Floris Bruynooghe wrote:
> >> On 27 June 2012 13:57, holger krekel <holger at merlinux.eu> wrote:
> >> > Setting resources as class attributes
> >> > -------------------------------------------
> >> >
> >> > If you want to make an attribute available on a test class, you can
> >> > use the resource_attr marker::
> >> >
> >> >    @pytest.mark.resource_attr("db")
> >> >    class TestClass:
> >> >        def test_something(self):
> >> >            #use self.db
> >>
> >> I'm not convinced of creating a special purpose mark for this.
> >> Firstly it seems like an anti-pattern in py.test to me, more like
> >> xUnit style.
> >
> > unittest/xUnit-compat is the main idea for this new marker. It would
> > work on pytest and unittest.TestCase classes alike.  It's also reminiscent
> > of Rob Collin's testscenario unittest-extension.
> >
> >> easily done with::
> >>
> >>    class TestClas(object):
> >>        @classmethod
> >>        def setup_class(cls, item):
> >>            cls.db = item.getresource('db')
> >
> > Not really.  Here we would need to check if the setup_class()
> > accepts an item parameter and setup_class methods do not follow
> > the hook-keyword-arg-calling convention.  Also passing an
> > item would be slightly arbitrary as the setup_class would
> > only be called once for all of its test items (functions).
> 
> Oh, that will teach me to talk about an API I haven't used in a long
> time without looking it up.  I thought a node (not item) was already
> passed in.  Still, I think it would look nicer if it was possible to
> get to the resources API from within .setup_module(module),
> .setup_class(cls) and .setup_method(self, method) rather then needing
> a new marker for this.  The first of these should not be a problem I
> guess, since it already has a node passed in.  For .setup_method() the
> method argument could have an item attribute.  But I guess
> .setup_class(cls) is the hardest.  Would it be tricky to inspect the
> arguments as done for hooks?

setup_module/setup_class/setup_method all receive native python objects,
not collection nodes.  We could stick node attributes somewhere (not sure if 
on functions - they can be invoked multiple times in case of parametrization).

If we stick attributes e.g. on a pytest.current.item/classnode/... we
are doing side-effect programming - some internals will set those
attributes (and should take care to remove it to avoid
misusage/confusion) and some other places will read it.  These days, i
prefer to design APIs that communicate neccesarry state directly and
to use higher-level declarations to state intents rather than do everything
through imperative programming.

/me does "import this" and sees: Although practicality beats purity ...

I am still fine to consider e. g. the introduction of a pytest.current
namespace.  It could lead to make setup_X methods more powerful::

    import pytest
    def setup_module():  # pytest accepts it to keep nose compat
        db = pytest.current.modulenode.getresource("db")

The "current" namespace could be set by the respective node setup
methods.  For classes it's the same idea::

    class TestClass:
        def setup_class(cls):
            cls.db = pytest.current.classnode.getresource("db")

Due to the non-declarative nature of this approach, however, i don't
see a way to rerun the testclass with multiple "db" instances.

On a side note, many Java programmers have gone from the old JUnit
approach to TestNG, see the wikipedia entries.  py.test rather
goes for similar ideas as TestNG.

best,
holger

> 
> >> Also, I realised this API provides for what is probably most of the
> >> cases of where I want dynamic resources:
> >>
> >> def pytest_setup_init(session):
> >>     for item in my_item_generator():
> >>         session.register_resource_factory(item.name, item)
> >
> > Not sure i understand this idea.  Is it intended as a mixture of
> > collection (my_item_generator) and setup (as the hook name suggests)?
> 
> My bad for writing a bad example, I shouldn't have used the word
> "item" in there.  Anyway the main point is that thanks to
> .register_resource_factory() taking the name of the resource as an
> argument I believe most, if not all, the cases where I wanted to
> create funcargs/resources without knowing what they where beforehand
> are solved.
> 
> 
> Regards,
> Floris
> 
> 
> -- 
> Debian GNU/Linux -- The Power of Freedom
> www.debian.org | www.gnu.org | www.kernel.org
> 



More information about the Pytest-dev mailing list