Hi Bruno, This is great! Just echoing what Brian said - simple and obvious, and I'm disappointed that I didn't see it myself. I've integrated your suggestion today and the teardown tests are now much simpler, so this definitely helped.
Would it be worth PR-ing this suggestion into the docs? My guess is that it would help many devs. Am happy to do the copypasta if you think it's worth it. Cheers, James On Thu, 7 Jan 2021, at 5:56 AM, Brian Okken wrote: > Bruno, > > This is brilliant in that it’s obvious now that I see it, but didn’t occur to > me before. > > Super cool. > > - Brian > >> On Jan 6, 2021, at 10:26 AM, Bruno Oliveira <nicodde...@gmail.com> wrote: >> >> Hi James, >> What I suggest you do in your case is to decouple your code from the >> fixture, so if you have something like this today: >> ` @pytest.fixture(scope="module") def my_work_reqs(): # some # complicated # setup # code yield x # some result # some # complicated # teardown # code ` >> You can write instead: >> ` @contextmanager def handle_work_reqs(): # some # complicated # setup # code try: yield x # some result finally: # some # complicated # teardown # code @pytest.fixture(scope="module") def my_work_reqs(): with handle_work_reqs() as x: yield x ` >> Now you can test `handle_work_reqs` normally, as it is not tied to the >> pytest framework. >> I like this approach in general, decoupling custom code from a framework is >> a great way to make it easier to test. >> HTH, >> Bruno. >> >> >> On Wed, Jan 6, 2021 at 2:37 PM James Cooke <m...@jamescooke.info> wrote: >>> Hi all, >>> >>> It's been a while since I've had to write a complicated and robust pytest >>> fixture and I'm struggling with testing the teardown / finalisation code. >>> >>> Instead of boring you with the [my-work-project] requirements of cleaning >>> up GCS after tests, I'll refer to the fixture in the docs >>> https://docs.pytest.org/en/stable/fixture.html#fixture-finalization-executing-teardown-code >>> : >>> >>> @pytest.fixture(scope="module") >>> def smtp_connection(): >>> smtp_connection = smtplib.SMTP("smtp.gmail.com", 587, timeout=5) >>> yield smtp_connection # provide the fixture value >>> print("teardown smtp") >>> smtp_connection.close() >>> >>> My (very old) usual strategy for testing teardown of a fixture that uses >>> `yield` would be: >>> >>> * Start test >>> >>> - Instantiate the fixture. >>> >>> - Manipulate the instance with `next()` to trigger the teardown. >>> >>> - Ensure that teardown was successful - in this case assert that the >>> SMTP connection returned when the fixture was instantiated was closed >>> successfully. >>> >>> Given that since v4.1 (https://github.com/pytest-dev/pytest/issues/4545), >>> the arrangement step of "Instantiate the fixture" does not work, could >>> someone point me at the recommended method of testing fixture teardown? >>> >>> I would like to ensure that teardown is resilient and can resolve multiple >>> conditions that can happen in [my-work-project]'s test suite. I can see >>> that there are multiple tests on fixtures in >>> https://github.com/pytest-dev/pytest/blob/48c9a96a03261e7cfa5aad0367a9186d9032904a/testing/python/fixtures.py >>> , are there any preferred / recommended / efficient methods in this file? >>> Alternatively, is there a way to by-pass the fixture wrapping that happens >>> that prevents it being callable? Should I be using >>> `smtp_connection.__pytest_wrapped__.obj()` to instantiate? (this seems bad) >>> >>> Any pointers / suggestions would be great. >>> >>> Thanks, >>> >>> James >>> >>> >>> _______________________________________________ >>> pytest-dev mailing list >>> pytest-dev@python.org >>> https://mail.python.org/mailman/listinfo/pytest-dev >> _______________________________________________ >> pytest-dev mailing list >> pytest-dev@python.org >> https://mail.python.org/mailman/listinfo/pytest-dev
_______________________________________________ pytest-dev mailing list pytest-dev@python.org https://mail.python.org/mailman/listinfo/pytest-dev