尝试使用 pytest 和 capsys 访问标准输出时出现 ValueError
ValueError while trying to access stdout using pytest and capsys
正在尝试在验证用户帐户的对象中测试本地方法的标准输出。
例如,
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 今天很弱)。
如果我做了一些愚蠢的事情,我深表歉意,但此时我很担心键盘的安全,所以我想我会伸出援手。任何 help/suggestions 表示赞赏。你可以 运行 我发布的这个测试用例,它应该给你与发布的相同的错误。
您的问题是您提供了补丁装饰器,但没有将相应的参数添加到测试函数中。这是正确的:
@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)
...
您的代码中发生的事情是固定装置 testdir
和 capsys
已被用作模拟参数(预期作为测试函数中的第一个参数),导致两者作为模拟对象而不是夹具。
旁注:如果pytest在这种情况下发出警告就好了,比如“你正在使用夹具名称作为修补对象的名称,也许你忘记添加修补对象参数?”...
请注意,我已将您示例代码中的断言替换为使用您的代码实际会通过的断言。
正在尝试在验证用户帐户的对象中测试本地方法的标准输出。
例如,
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 今天很弱)。
如果我做了一些愚蠢的事情,我深表歉意,但此时我很担心键盘的安全,所以我想我会伸出援手。任何 help/suggestions 表示赞赏。你可以 运行 我发布的这个测试用例,它应该给你与发布的相同的错误。
您的问题是您提供了补丁装饰器,但没有将相应的参数添加到测试函数中。这是正确的:
@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)
...
您的代码中发生的事情是固定装置 testdir
和 capsys
已被用作模拟参数(预期作为测试函数中的第一个参数),导致两者作为模拟对象而不是夹具。
旁注:如果pytest在这种情况下发出警告就好了,比如“你正在使用夹具名称作为修补对象的名称,也许你忘记添加修补对象参数?”...
请注意,我已将您示例代码中的断言替换为使用您的代码实际会通过的断言。