尝试使用pytest和capsys访问stdout时发生ValueError

时间:2020-06-21 02:15:57

标签: python-3.x mocking pytest stdout valueerror

尝试在验证用户帐户的对象中测试本地方法的标准输出。

例如,

class Foo:
    def __init__(self, bar, baz):
        self.bar = bar
        if baz:
            self.something = self.load_something()
        else:
            print('Error initializing')

    def load_something(self):
        return ''

    def make_subprocess_call(self):
        return 'stdout', 'stderr'
    
    def confirm_something(self):
        subprocess_stdout, subprocess_stderr = self.make_subprocess_call()
        if subprocess_stdout:
            print('good output')
        else:
            print('err output', subprocess_stderr)

然后进行测试:

from Foo_Class_File import Foo
import mock
import pytest

@mock.patch('Foo_Class_File.Foo.load_something', return_value = {'a': 'b'})
@mock.patch('Foo_Class_File.Foo.make_subprocess_call', return_value=('more stdout', 'more_stderr'))
def test_confirm_something(testdir, capsys):
    test_foo = Foo(testdir, True)
    test_foo.confirm_something()
    out, err = capsys.readouterr()
    assert out == 'more stdout'
    assert err == 'more_stderr'

然后运行:

python3 -m pytest test_foo_file.py

给予:

============================================================================== FAILURES ===============================================================================
_______________________________________________________________________ test_confirm_something ________________________________________________________________________

testdir = <MagicMock name='make_subprocess_call' id='140533346667632'>, capsys = <MagicMock name='load_something' id='140533346970400'>

    @mock.patch('Foo_Class_File.Foo.load_something', return_value = {'a': 'b'})
    @mock.patch('Foo_Class_File.Foo.make_subprocess_call', return_value=('more stdout', 'more_stderr'))
    def test_confirm_something(testdir, capsys):
        test_foo = Foo(testdir, True)
        test_foo.confirm_something()
>       out, err = capsys.readouterr()
E       ValueError: not enough values to unpack (expected 2, got 0)

blah.py:10: ValueError
------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------
good output
======================================================================= short test summary info =======================================================================
FAILED test_foo_file.py::test_confirm_something - ValueError: not enough values to unpack (expected 2, got 0)
========================================================================== 1 failed in 0.11s ==========================================================================

我真的很困惑,因为它说正在捕获标准输出?

我认为这与实例化对象然后调用方法有关,因为如果只有对象,我用capsys捕获就没有问题,但是一旦我尝试实例化它并调用方法,您将看到上面会发生什么。我找不到在线或文档中的类似案例,这并不是因为缺乏尝试(或者我的Google foo今天很虚弱)。

很抱歉,如果我做一些愚蠢的事情,但在这一点上,我担心键盘的安全性并认为我会伸出援手。任何帮助/建议表示赞赏。您可以运行我发布的这个测试用例,它应该给您与发布的相同的错误。

1 个答案:

答案 0 :(得分:1)

您的问题是您提供了补丁装饰器,但没有将各自的参数添加到测试函数中。这是正确的:

@mock.patch('Foo_Class_File.Foo.load_something', return_value = {'a': 'b'})
@mock.patch('Foo_Class_File.Foo.make_subprocess_call', return_value=('more stdout', 'more_stderr'))
def test_confirm_something(mocked_call, mocked_load, testdir, capsys):  # note the additional arguments
    test_foo = Foo(testdir, True)
    test_foo.confirm_something()
    out, err = capsys.readouterr()
    assert out == 'good output\n'
    assert err == ''

或者,或者:

@mock.patch('Foo_Class_File.Foo.load_something')
@mock.patch('Foo_Class_File.Foo.make_subprocess_call')
def test_confirm_something(mocked_call, mocked_load, testdir, capsys):
    mocked_call.return_value = ('more stdout', 'more_stderr')
    mocked_load.return_value = {'a': 'b'}
    test_foo = Foo(testdir, True)
    ...

您的代码中发生的事情是,夹具testdircapsys已被用作模拟参数(它们应作为测试函数中的第一个参数),导致两者都是模拟对象而不是夹具。

附带说明:如果在这种情况下pytest发出警告,那会很好,例如“您正在使用灯具名称作为已修补对象的名称,也许您忘记添加已修补的对象对象参数?” ...

请注意,我已将示例代码中的断言替换为实际上将使用您的代码传递的断言。

相关问题