[TIP] (no subject)
holger krekel
holger at merlinux.eu
Sun Mar 29 11:09:11 PDT 2015
On Sun, Mar 29, 2015 at 12:38 -0400, dpb dpb wrote:
> Thanks to both of you.
>
> I understand that it's normally the case to want complete isolation between
> tests.
>
> But on occasion it's useful to run tests on a series of cumulative changes
> to state. That means forfeiting test independence, or anyway building it
> into the sequence in which tests are run. The alternatives seem to be
> placing many asserts into each test function, or running tests based on
> simulated data.
>
> I see that I can keep track cumulative changes in state pretty simply,
> using a non-test class (rather than the test class) to define the
> state-bearing object.
Yes, more precisely you can do something like this:
import pytest
class IncState:
""" you can store state on attributes and pass them from test to test. """
@pytest.fixture(scope="module")
def incstate():
return IncState()
def test_one(incstate):
incstate.x = 1
def test_two(incstate):
assert incstate.x == 1
incstate.x += 1
def test_three(incstate):
assert incstate.x == 2
With pytest it's safe to do it because it guarantees execution in source order.
Other test runners depend on dictionary order (of the module globals() or a class dict)
and thus are typically less predictable. Of course this pattern does violate test
isolation and i have very rarely used the above incremental pattern when i wanted
to avoid having one large test containing all the increments. Rarely
means twice or so in my 15 years of writing thousands of tests.
best,
holger
> - dpb
>
> On Sun, Mar 29, 2015 at 12:01 PM, Ned Batchelder <ned at nedbatchelder.com>
> wrote:
>
> > On 3/29/15 4:57 AM, dpb dpb wrote:
> >
> > Something I do not see addressed explicitly in the Pytest docs is this
> > behavior: Unlike normal class writing in Python 3, changing the value of a
> > class attribute in one function does not leave it changed in test functions
> > that are called subsequently:
> >
> > As Holger mentioned, a new TestExample instance is created for each
> > test. This is how all the test runners work, because you want isolation
> > between your tests. One of the principles of the xUnit style of testing is
> > that each test is independent of all other tests. You want to be able to
> > run a single test and not have it depend on the results of previous tests.
> >
> > --Ned.
> >
> > # test_pytest_class_attributes.py
> >> """Test the setting of class attributes."""
> >> class TestExample():
> >> def setup(self):
> >> self.attribute = 1
> >
> >
> >> def test_changing_attr(self):
> >> """Change attribute on object."""
> >> self.attribute = 2
> >> assert self.attribute == 2
> >
> >
> >> def test_attr_is_changed(self):
> >> """Assume attribute is changed."""
> >> assert self.attribute == 2
> >
> >
> >> def test_attr_is_unchanged(self):
> >> """Assume attribute is unchanged."""
> >> assert self.attribute == 1
> >
> >
> > Output:
> >
> > $ py.test test_pytest_class_attributes.py -v
> >> ============================= test session starts
> >> ==============================
> >> platform darwin -- Python 3.4.1 -- py-1.4.25 -- pytest-2.6.3 --
> >> /Users/dpb/py34/bin/python3.4
> >> collected 3 items
> >> test_pytest_class_attributes.py::TestExample::test_changing_attr PASSED
> >> test_pytest_class_attributes.py::TestExample::test_attr_is_changed FAILED
> >> test_pytest_class_attributes.py::TestExample::test_attr_is_unchanged
> >> PASSED
> >> =================================== FAILURES
> >> ===================================
> >> _______________________ TestExample.test_attr_is_changed
> >> _______________________
> >> self = <test_pytest_class_attributes.TestExample object at 0x10dd98ef0>
> >> def test_attr_is_changed(self):
> >> """Test whether attribute is changed."""
> >> > assert self.attribute == 2
> >> E assert 1 == 2
> >> E + where 1 = <test_pytest_class_attributes.TestExample object at
> >> 0x10dd98ef0>.attribute
> >
> >
> >
> > test_pytest_class_attributes.py:14: AssertionError
> >> ====================== 1 failed, 2 passed in 0.02 seconds
> >> ======================
> >> $
> >
> >
> > Is there special syntax or some special structure to make class
> > attributes behave In Pytest as they do in an ordinary Python class? Example:
> >
> > # display_class_attributes.py
> >> """Test the setting of class attributes."""
> >
> >
> >> class TestExample():
> >> def __init__(self):
> >> self.attribute = 1
> >
> >
> >> def test_changing_attr(self):
> >> """Change attribute on object."""
> >> self.attribute = 2
> >> assert self.attribute == 2
> >> print('Finished test_changing_attr.\n')
> >
> >
> >> def test_attr_is_changed(self):
> >> """Test whether attribute is changed."""
> >> assert self.attribute == 2
> >> print('Finished test_attr_is_changed.\n')
> >
> >
> >> def test_attr_is_unchanged(self):
> >> """Test whether attribute is unchanged."""
> >> assert self.attribute == 1
> >> print('Finiahed test_attr_is_unchanged.\n')
> >
> >
> >> t = TestExample()
> >> t.test_changing_attr()
> >> t.test_attr_is_changed()
> >> t.test_attr_is_unchanged()
> >
> >
> > Output:
> >
> > > $ python display_class_attributes.py
> > >
> > > self.attribute == 2: True
> > >
> > > self.attribute == 2: True
> > >
> > > self.attribute == 1: False
> > >
> > > $
> >
> > Thanks.
> >
> > - dpb
> >
> >
> > _______________________________________________
> > testing-in-python mailing listtesting-in-python at lists.idyll.orghttp://lists.idyll.org/listinfo/testing-in-python
> >
> >
> >
> > _______________________________________________
> > testing-in-python mailing list
> > testing-in-python at lists.idyll.org
> > http://lists.idyll.org/listinfo/testing-in-python
> >
> >
> _______________________________________________
> testing-in-python mailing list
> testing-in-python at lists.idyll.org
> http://lists.idyll.org/listinfo/testing-in-python
--
about me: http://holgerkrekel.net/about-me/
contracting: http://merlinux.eu
More information about the testing-in-python
mailing list