What's the benefit of a fixture with function scope and no teardown code?

Question:

What’s advantage of a (default) function-scope fixture without teardown code? Why not just call the function at the beginning of the test?

For example, what’s the benefit of writing:

@pytest.fixture
def smtp():
    return smtplib.SMTP("smtp.gmail.com")

def test_ehlo(smtp):
    response, msg = smtp.ehlo()
    # ...

instead of simply:

def create_smtp():
    return smtplib.SMTP("smtp.gmail.com")

def test_ehlo():
    smtp = create_smtp()
    response, msg = smtp.ehlo()
    # ...

I understand why fixtures are useful when we need teardown code. I also understand why fixtures with scope other than function are useful: we may want to reuse the same “external” object in multiple tests (to save the time it takes to create it; or perhaps even to maintain its state — although that seems to be rather dangerous since this creates an hard-to-see coupling between separate tests).

Asked By: max

||

Answers:

What’s advantage of a (default) function-scope fixture without
teardown code? Why not just call the function at the beginning of the
test?

Saving vertical space.

Consider something like this, where you have more than one fixture per test:

import pytest


@pytest.fixture
def value1():
  return 1

@pytest.fixture
def value2():
  return 2

@pytest.fixture
def value3():
  return 3


def test_values(value1, value2, value3):
    assert value1 == 1
    assert value2 == 2
    assert value3 == 3

If we were to do this your way:

def test_values():
    v1 = value1()
    v2 = value2()
    v3 = value3()

    assert v1 == 1
    assert v2 == 2
    assert v3 == 3

That’s three extra lines of code. Not a big deal, but then what if you had 10 tests that needed value1, value2 and value3? Now you have 30 extra lines of vertical space for basically no reason.

Obviously, both of our examples are overly simplified (I could just have done the call and assert inline), but I think it’s straightforward to see how this could have an impact with real code.

Answered By: Jack

I had a similar question when I started using it. Here’s my experience:

  • Fixtures can be set to autouse=True, i.e., trigger automatically that may not be possible with an inline call. This is useful in some cases.
  • Fixtures add readability, at least for me. Looking at the signature of the test, one can figure out what initialisations are a pre-requisite for a given test. In that sense, it also help keep the test and it’s initialisation isolated.
Answered By: Sharad

I believe that one of the most important advantage of function-scoped fixtures is consistency. It is much more readable and logical if all your fixtures (no matter of they scope or tear-down code) are used in exactly same way.

Also if in some point in future you’ll decided to change the scope of this fixture or to add some tear-down code to it then you would not need to change any test cases, only the code of the fixture.

Answered By: Pax0r

Look at this answer:
https://stackoverflow.com/a/67636207/11277611
I’m not so liking fixtures, but one advatage – it’s reusability.
If you have some function with long computtion – you can define it once in fixture and reuse it every time in the tests.
Surely you can do this with a regular function, IMO, it’s a kind of test.

Answered By: Давид Шико
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.