9

I am using a pytest fixture to mock up command-line arguments for testing a script. This way the arguments shared by each test function would only need to be declared in one place. I'm also trying to use pytest's capsys to capture output printed by the script. Consider the following silly example.

from __future__ import print_function
import pytest
import othermod
from sys import stdout


@pytest.fixture
def shared_args():
    args = type('', (), {})()
    args.out = stdout
    args.prefix = 'dude:'
    return args


def otherfunction(message, prefix, stream):
    print(prefix, message, file=stream)


def test_dudesweet(shared_args, capsys):
    otherfunction('sweet', shared_args.prefix, shared_args.out)
    out, err = capsys.readouterr()
    assert out == 'dude: sweet\n'

Here, capsys does not capture sys.stderr properly. If I move from sys import stdout and args.out = stdout directly into the test function, things work as expected. But this makes things much messier, as I have to re-declare these statements for each test. Am I doing something wrong? Can I use capsys with fixtures?

Daniel Standage
  • 8,136
  • 19
  • 69
  • 116

1 Answers1

-1

Fixture is invoked before test is run. In your example, shared_args fixture is reading stdout before otherfunction can write anything to stdout.

One way to fix your problem is to make your fixture return a function which can do what you want it to do. You can scope the fixture according to your use case.

from __future__ import print_function
import pytest
from sys import stdout
import os


@pytest.fixture(scope='function')
def shared_args():
    def args_func():
        args = type('', (), {})()
        args.out = stdout
        args.prefix = 'dude:'
        return args
    return args_func


def otherfunction(message, prefix, stream):
    print(prefix, message, file=stream)


def test_dudesweet(shared_args, capsys):
    prefix, out = shared_args().prefix, shared_args().out
    otherfunction('sweet', prefix, out)
    out, err = capsys.readouterr()
    assert out == 'dude: sweet\n'

You are not using capsys.readouterr() correctly. See the correct usage of capsys here: https://stackoverflow.com/a/26618230/2312300

SilentGuy
  • 1,867
  • 17
  • 27