简体   繁体   中英

Using pytest fixture from common test function

I have some unittest -based code that currently looks like this :

class TestMain(TestCase):
    def run_prog(self, args):
        with TemporaryFile() as stdout:
            old_stdout = sys.stdout
            try:
                main.main()
                stdout.seek(0)
                stdout_data = stdout.read()
            finally:
                sys.stdout = old_stdout
        return stdout_data

    def test_one(self):
        out = self.run_prog(...)

    def test_two(self):
        out = self.run_prog(...)

    def test_three(self):
        out = self.run_prog(...)

run_prog invokes the "main" program under test and manually captures its stdout.

I'm in the process of converting this project to pytest , but this last piece has pushed the limits of my understanding of pytest fixtures.

I understand that pytest has full support for capturing stdout/stderr and I would like to leverage this.

The problem is, their examples work on a test-function level:

def test_myoutput(capfd):
    do_something
    captured = capsys.readouterr()
    assert captured.out == "hello\n"
    assert captured.err == "world\n"

In my case, run_prog is used 42 times, so I'm trying to use the fixture starting at run_prog -- the calling functions ideally don't need to bother with capsys / capfd .

Is there a way to "invoke" the fixture from my run_prog helper? Or do I need to add capfd to all 42 tests and pass it to run_prog ?

You can define an autouse fixture that will store the CaptureFixture object (returned by the capsys fixture) as an instance property:

class TestMain(TestCase):

    @pytest.fixture(autouse=True)
    def inject_capsys(self, capsys):
        self._capsys = capsys

    def run_prog(self, args):
        main.main()
        return self._capsys.out

    def test_out(self):
        assert self.run_prog('spam') == 'eggs'

The TestMain.inject_capsys fixture will be rerun for each test, guaranteeing the test isolation (no output from test_one will be leaked in test_two etc).

Here's a slight variation on hoefling's answer that gives a little more control over the scope of the capsys fixture.

It uses request.getfixturevalue() to retrieve the fixture at function invocation time:

import pytest
import sys

class TestMain:
    @pytest.fixture(autouse=True)
    def inject_request(self, request):
        self.request = request

    def run_prog(self, message):
        capfd = self.request.getfixturevalue('capfd')

        sys.stdout.write(message)

        captured = capfd.readouterr()
        assert captured.out == message

    def test_one(self):
        self.run_prog("Hello world!")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM