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