- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
注意:有关我的设置(python 版本、模块等)的所有详细信息都列在问题底部。
如果这个问题很明显,请提前致歉,但我已经为此苦苦挣扎了好几天。希望有人可以阐明一些新的观点。
我正在为我的个人项目从 unittest
-> pytest
转换单元测试。以前我使用的是内置的 unittest.mock
模块,但现在我正在尝试使用 pytest-mock
插件。
我有一种潜移默化的感觉,我的测试正在将模拟对象泄漏到彼此中。
原因如下:
高级细节:
# Python version
Python 3.5.2
# Pytest version ( and plugins )
pytest==3.0.7
pytest-benchmark==3.1.0a2
pytest-catchlog==1.2.2
pytest-cov==2.4.0
pytest-ipdb==0.1.dev2
pytest-leaks==0.2.2
pytest-mock==1.6.0
pytest-rerunfailures==2.1.0
pytest-sugar==0.8.0
pytest-timeout==1.2.0
python-dateutil==2.6.0
python-dbusmock==0.16.7
当我使用以下命令运行测试时:
py.test --pdb --showlocals -v -R : -k test_subprocess.py
在我们到达 test_subprocess_check_command_type
之前一切都很好。此时我收到以下错误:
# Set mock return types
# mock_map_type_to_command.return_value = int
# action
with pytest.raises(TypeError) as excinfo:
scarlett_os.subprocess.Subprocess(test_command,
name=test_name,
fork=test_fork,
> run_check_command=True)
E Failed: DID NOT RAISE <class 'TypeError'>
excinfo = <[AttributeError("'ExceptionInfo' object has no attribute 'typename'") raised in repr()] ExceptionInfo object at 0x7f8c380f9dc0>
mock_fork = <Mock name='mock_fork' id='140240122195184'>
mock_logging_debug = <Mock name='mock_logging_debug' id='140240128747640'>
mock_map_type_to_command = <Mock name='mock_map_type_to_command' id='140240122785112'>
mocker = <pytest_mock.MockFixture object at 0x7f8c329f07a8>
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f8c329f0810>
self = <tests.test_subprocess.TestScarlettSubprocess object at 0x7f8c32aaac20>
test_command = ['who', '-b']
test_fork = False
test_name = 'test_who'
tests/test_subprocess.py:267: Failed
tests/test_subprocess.py::TestScarlettSubprocess.test_subprocess_check_command_type ⨯ 100% ██████████
但是!
如果我过滤掉除有问题的测试之外的所有其他测试,那么我会得到:
通过 py.test --pdb --showlocals -v -R : -k test_subprocess_check_command_type
pi@0728af726f1f:~/dev/bossjones-github/scarlett_os$ py.test --pdb --showlocals -v -R : -k test_subprocess_check_command_type
/usr/local/lib/python3.5/site-packages/_pdbpp_path_hack/pdb.py:4: ResourceWarning: unclosed file <_io.TextIOWrapper name='/usr/local/lib/python3.5/site-packages/pdb.py' mode='r' encoding='UTF-8'>
os.path.dirname(os.path.dirname(__file__)), 'pdb.py')).read(), os.path.join(
Test session starts (platform: linux, Python 3.5.2, pytest 3.0.7, pytest-sugar 0.8.0)
cachedir: .cache
benchmark: 3.1.0a2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /home/pi/dev/bossjones-github/scarlett_os, inifile: setup.cfg
plugins: timeout-1.2.0, sugar-0.8.0, rerunfailures-2.1.0, mock-1.6.0, leaks-0.2.2, ipdb-0.1.dev2, cov-2.4.0, catchlog-1.2.2, benchmark-3.1.0a2
timeout: 60.0s method: signal
NOTE: DBUS_SESSION_BUS_ADDRESS environment var not found!
[DBUS_SESSION_BUS_ADDRESS]: unix:path=/tmp/dbus_proxy_outside_socket
tests/test_subprocess.py::TestScarlettSubprocess.test_subprocess_check_command_type ✓ 100% ██████████
Results (8.39s):
1 passed
190 deselected
pi@0728af726f1f:~/dev/bossjones-github/scarlett_os$
我还尝试手动注释掉以下 2 个测试,它们使我能够再次成功运行所有测试:
test_subprocess_init
test_subprocess_map_type_to_command
有人能看出我的设置有什么明显的错误吗?我已经阅读了几篇关于“在哪里模拟”的博客文章,并多次查看了文档,不确定我错过了什么。 https://docs.python.org/3/library/unittest.mock.html
我的设置详情
这里是解决这个问题可能需要的一切。让我知道是否需要提供更多信息!
另外...请原谅我的代码看起来多么困惑以及所有的注释 block 。当我学习新东西时,我是一个记笔记的人……在不久的将来,我会让一切变得更 pythonic 和更干净:)
我的代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Scarlett Dbus Service. Implemented via MPRIS D-Bus Interface Specification."""
from __future__ import with_statement, division, absolute_import
import os
import sys
from scarlett_os.exceptions import SubProcessError
from scarlett_os.exceptions import TimeOutError
import logging
from scarlett_os.internal.gi import GObject
from scarlett_os.internal.gi import GLib
logger = logging.getLogger(__name__)
def check_pid(pid):
"""Check For the existence of a unix pid."""
try:
os.kill(pid, 0)
except OSError:
return False
else:
return True
class Subprocess(GObject.GObject):
"""
GObject API for handling child processes.
:param command: The command to be run as a subprocess.
:param fork: If `True` this process will be detached from its parent and
run independent. This means that no excited-signal will be emited.
:type command: `list`
:type fork: `bool`
"""
__gtype_name__ = 'Subprocess'
__gsignals__ = {
'exited': (GObject.SignalFlags.RUN_LAST, None, (GObject.TYPE_INT, GObject.TYPE_INT))
}
def __init__(self, command, name=None, fork=False, run_check_command=True):
"""Create instance of Subprocess."""
GObject.GObject.__init__(self)
self.process = None
self.pid = None
if not fork:
self.stdout = True
self.stderr = True
else:
self.stdout = False
self.stderr = False
self.forked = fork
# Verify that command is properly formatted
# and each argument is of type str
if run_check_command:
self.check_command_type(command)
self.command = command
self.name = name
logger.debug("command: {}".format(self.command))
logger.debug("name: {}".format(self.name))
logger.debug("forked: {}".format(self.forked))
logger.debug("process: {}".format(self.process))
logger.debug("pid: {}".format(self.pid))
if fork:
self.fork()
# TODO: Add these arguments so we can toggle stdout
# def spawn_command(self, standard_input=False, standard_output=False, standard_error=False):
def spawn_command(self):
# DO_NOT_REAP_CHILD
# Don't reap process automatically so it is possible to detect when it is closed.
return GLib.spawn_async(self.command,
flags=GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD
)
def map_type_to_command(self, command):
"""Return: Map after applying type to several objects in an array"""
# NOTE: In python3, many processes that iterate over iterables return iterators themselves.
# In most cases, this ends up saving memory, and should make things go faster.
# cause of that, we need to call list() over the map object
return list(map(type, command))
def check_command_type(self, command):
types = self.map_type_to_command(command)
if type(types) is not list:
raise TypeError("Variable types should return a list in python3. Got: {}".format(types))
# NOTE: str is a built-in function (actually a class) which converts its argument to a string.
# string is a module which provides common string operations.
# source: http://stackoverflow.com/questions/2026038/relationship-between-string-module-and-str
for t in types:
if t is not str:
raise TypeError("Executables and arguments must be str objects. types: {}".format(t))
logger.debug("Running Command: %r" % " ".join(command))
return True
def run(self):
"""Run the process."""
# NOTE: DO_NOT_REAP_CHILD: the child will not be automatically reaped;
# you must use g_child_watch_add yourself (or call waitpid or handle `SIGCHLD` yourself),
# or the child will become a zombie.
# source:
# http://valadoc.org/#!api=glib-2.0/GLib.SpawnFlags.DO_NOT_REAP_CHILD
# NOTE: SEARCH_PATH: argv[0] need not be an absolute path, it will be looked for in the user's PATH
# source:
# http://lazka.github.io/pgi-docs/#GLib-2.0/flags.html#GLib.SpawnFlags.SEARCH_PATH
self.pid, self.stdin, self.stdout, self.stderr = self.spawn_command()
logger.debug("command: {}".format(self.command))
logger.debug("stdin: {}".format(self.stdin))
logger.debug("stdout: {}".format(self.stdout))
logger.debug("stderr: {}".format(self.stderr))
logger.debug("pid: {}".format(self.pid))
# close file descriptor
self.pid.close()
print(self.stderr)
# NOTE: GLib.PRIORITY_HIGH = -100
# Use this for high priority event sources.
# It is not used within GLib or GTK+.
watch = GLib.child_watch_add(GLib.PRIORITY_HIGH,
self.pid,
self.exited_cb)
return self.pid
def exited_cb(self, pid, condition):
if not self.forked:
self.emit('exited', pid, condition)
def fork(self):
"""Fork the process."""
try:
# first fork
pid = os.fork()
if pid > 0:
logger.debug('pid greater than 0 first time')
sys.exit(0)
except OSError as e:
logger.error('Error forking process first time')
sys.exit(1)
# Change the current working directory to path.
os.chdir("/")
# Description: setsid() creates a new session if the calling process is not a process group leader.
# The calling process is the leader of the new session,
# the process group leader of the new process group,
# and has no controlling terminal.
# The process group ID and session ID of the calling process are set to the PID of the calling process.
# The calling process will be the only process in this new process group and in this new session.
# Return Value: On success, the (new) session ID of the calling process is returned.
# On error, (pid_t) -1 is returned, and errno is set to indicate the error.
os.setsid()
# Set the current numeric umask and return the previous umask.
os.umask(0)
try:
# second fork
pid = os.fork()
if pid > 0:
logger.debug('pid greater than 0 second time')
sys.exit(0)
except OSError as e:
logger.error('Error forking process second time')
sys.exit(1)
我的测试:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
test_subprocess
----------------------------------
"""
import os
import sys
import pytest
import scarlett_os
# import signal
# import builtins
# import re
class TestScarlettSubprocess(object):
'''Units tests for Scarlett Subprocess, subclass of GObject.Gobject.'''
def test_check_pid_os_error(self, mocker):
# Feels like mocks are leaking into other tests,
# stop mock before starting each test function
mocker.stopall()
# Setup mock objects
kill_mock = mocker.MagicMock(name=__name__ + "_kill_mock_OSError")
kill_mock.side_effect = OSError
# patch things
mocker.patch.object(scarlett_os.subprocess.os, 'kill', kill_mock)
# When OSError occurs, throw False
assert not scarlett_os.subprocess.check_pid(4353634632623)
# Verify that os.kill only called once
assert kill_mock.call_count == 1
def test_check_pid(self, mocker):
# Feels like mocks are leaking into other tests,
# stop mock before starting each test function
mocker.stopall()
# Setup mock objects
kill_mock = mocker.MagicMock(name=__name__ + "_kill_mock")
mocker.patch.object(scarlett_os.subprocess.os, 'kill', kill_mock)
result = scarlett_os.subprocess.check_pid(123)
assert kill_mock.called
# NOTE: test against signal 0
# sending the signal 0 to a given PID just checks if any
# process with the given PID is running and you have the
# permission to send a signal to it.
kill_mock.assert_called_once_with(123, 0)
assert result is True
# FIXME: I THINK THIS GUYS IS LEAKING MOCK OBJECTS
def test_subprocess_init(self, mocker):
# Feels like mocks are leaking into other tests,
# stop mock before starting each test function
mocker.stopall()
mock_check_command_type = MagicMock(name="mock_check_command_type")
mock_check_command_type.return_value = True
mock_fork = mocker.MagicMock(name="mock_fork")
mock_logging_debug = mocker.MagicMock(name="mock_logging_debug")
# mock
mocker.patch.object(scarlett_os.subprocess.logging.Logger, 'debug', mock_logging_debug)
mocker.patch.object(scarlett_os.subprocess.Subprocess, 'check_command_type', mock_check_command_type)
mocker.patch.object(scarlett_os.subprocess.Subprocess, 'fork', mock_fork)
# NOTE: On purpose this is an invalid cmd. Should be of type array
test_command = ['who']
test_name = 'test_who'
test_fork = False
s_test = scarlett_os.subprocess.Subprocess(test_command,
name=test_name,
fork=test_fork)
# action
assert s_test.check_command_type(test_command) is True
mock_check_command_type.assert_called_with(['who'])
assert not s_test.process
assert not s_test.pid
assert s_test.name == 'test_who'
assert not s_test.forked
assert s_test.stdout is True
assert s_test.stderr is True
mock_logging_debug.assert_any_call("command: ['who']")
mock_logging_debug.assert_any_call("name: test_who")
mock_logging_debug.assert_any_call("forked: False")
mock_logging_debug.assert_any_call("process: None")
mock_logging_debug.assert_any_call("pid: None")
mock_fork.assert_not_called()
# FIXME: I THINK THIS GUYS IS LEAKING MOCK OBJECTS
def test_subprocess_map_type_to_command(self, mocker):
"""Using the mock.patch decorator (removes the need to import builtins)"""
# Feels like mocks are leaking into other tests,
# stop mock before starting each test function
mocker.stopall()
mock_check_command_type = mocker.MagicMock(name="mock_check_command_type")
mock_check_command_type.return_value = True
mock_fork = mocker.MagicMock(name="mock_fork")
mock_logging_debug = mocker.MagicMock(name="mock_logging_debug")
# mock
mocker.patch.object(scarlett_os.subprocess.logging.Logger, 'debug', mock_logging_debug)
mocker.patch.object(scarlett_os.subprocess.Subprocess, 'check_command_type', mock_check_command_type)
mocker.patch.object(scarlett_os.subprocess.Subprocess, 'fork', mock_fork)
# NOTE: On purpose this is an invalid cmd. Should be of type array
test_command = ["who", "-b"]
test_name = 'test_who'
test_fork = False
# create subprocess object
s_test = scarlett_os.subprocess.Subprocess(test_command,
name=test_name,
fork=test_fork)
mocker.spy(s_test, 'map_type_to_command')
assert isinstance(s_test.map_type_to_command(test_command), list)
assert s_test.map_type_to_command.call_count == 1
assert s_test.check_command_type(test_command)
assert s_test.check_command_type(
test_command) == mock_check_command_type.return_value
def test_subprocess_check_command_type(self, mocker):
"""Using the mock.patch decorator (removes the need to import builtins)"""
# Feels like mocks are leaking into other tests,
# stop mock before starting each test function
mocker.stopall()
test_command = ["who", "-b"]
test_name = 'test_who'
test_fork = False
# mock
mock_map_type_to_command = mocker.MagicMock(name="mock_map_type_to_command")
# mock_map_type_to_command.return_value = int
mock_map_type_to_command.side_effect = [int, [int, int]]
mock_fork = mocker.MagicMock(name="mock_fork")
mock_logging_debug = mocker.MagicMock(name="mock_logging_debug")
mocker.patch.object(scarlett_os.subprocess.logging.Logger, 'debug', mock_logging_debug)
mocker.patch.object(scarlett_os.subprocess.Subprocess, 'map_type_to_command', mock_map_type_to_command)
mocker.patch.object(scarlett_os.subprocess.Subprocess, 'fork', mock_fork)
# action
with pytest.raises(TypeError) as excinfo:
scarlett_os.subprocess.Subprocess(test_command,
name=test_name,
fork=test_fork,
run_check_command=True)
assert str(
excinfo.value) == "Variable types should return a list in python3. Got: <class 'int'>"
with pytest.raises(TypeError) as excinfo:
scarlett_os.subprocess.Subprocess(test_command,
name=test_name,
fork=test_fork,
run_check_command=True)
assert str(
excinfo.value) == "Executables and arguments must be str objects. types: <class 'int'>"
我的文件夹结构(注意我删除了一些东西,因为它过于冗长):
pi@0728af726f1f:~/dev/bossjones-github/scarlett_os$ tree -I *.pyc
.
├── requirements_dev.txt
├── requirements_test_experimental.txt
├── requirements_test.txt
├── requirements.txt
├── scarlett_os
│ ├── automations
│ │ ├── __init__.py
│ │ └── __pycache__
│ ├── commands.py
│ ├── compat.py
│ ├── config.py
│ ├── const.py
│ ├── core.py
│ ├── emitter.py
│ ├── exceptions.py
│ ├── __init__.py
│ ├── internal
│ │ ├── debugger.py
│ │ ├── deps.py
│ │ ├── encoding.py
│ │ ├── formatting.py
│ │ ├── gi.py
│ │ ├── __init__.py
│ │ ├── path.py
│ │ ├── __pycache__
│ │ └── system_utils.py
│ ├── listener.py
│ ├── loader.py
│ ├── logger.py
│ ├── log.py
│ ├── __main__.py
│ ├── mpris.py
│ ├── player.py
│ ├── __pycache__
│ ├── receiver.py
│ ├── speaker.py
│ ├── subprocess.py
│ ├── tasker.py
│ ├── tools
│ │ ├── __init__.py
│ │ ├── package.py
│ │ ├── __pycache__
│ │ └── verify.py
│ └── utility
│ ├── audio.py
│ ├── dbus_runner.py
│ ├── dbus_utils.py
│ ├── distance.py
│ ├── dt.py
│ ├── file.py
│ ├── generators.py
│ ├── gnome.py
│ ├── __init__.py
│ ├── location.py
│ ├── __pycache__
│ ├── temperature.py
│ ├── threadmanager.py
│ ├── thread.py
│ ├── unit_system.py
│ └── yaml.py
├── setup.cfg
├── setup.py
├── tests
│ ├── common_integration.py
│ ├── common.py
│ ├── helpers
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ ├── test_config_validation.py
│ │ ├── test_entity.py
│ │ └── test_init.py
│ ├── __init__.py
│ ├── integration
│ │ ├── baseclass.py
│ │ ├── conftest.py
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ ├── README.md
│ │ ├── stubs.py
│ │ ├── test_integration_end_to_end.py
│ │ ├── test_integration_listener.py
│ │ ├── test_integration_mpris.py
│ │ ├── test_integration_player.py
│ │ ├── test_integration_tasker.py
│ │ ├── test_integration_tasker.py.enable_sound.diff
│ │ └── test_integration_threadmanager.py
│ ├── internal
│ │ ├── __init__.py
│ │ ├── __pycache__
│ │ ├── test_deps.py
│ │ ├── test_encoding.py
│ │ └── test_path.py
│ ├── performancetests
│ │ ├── baseclass.py
│ │ ├── __init__.py
│ │ └── __pycache__
│ ├── __pycache__
│ ├── run_all_tests
│ ├── run_dbus_tests.sh
│ ├── test_cli.py
│ ├── test_commands.py
│ ├── testing_config
│ │ └── custom_automations
│ │ ├── light
│ │ │ └── test.py
│ │ └── switch
│ │ └── test.py
│ ├── test_listener.py
│ ├── test_mpris.py
│ ├── test_player.py
│ ├── test_scarlett_os.py
│ ├── test_speaker.py
│ ├── test_subprocess.py
│ ├── test_tasker.py
│ ├── test_threadmanager.py
│ ├── tools_common.py
│ ├── unit_scarlett_os.py
│ └── utility
│ ├── __init__.py
│ ├── __pycache__
│ ├── test_dbus_utils.py
│ ├── test_distance.py
│ ├── test_dt.py
│ ├── test_gnome.py
│ ├── test_init.py
│ ├── test_location.py
│ ├── test_unit_system.py
│ └── test_yaml.py
67 directories, 256 files
pi@0728af726f1f:~/dev/bossjones-github/scarlett_os$
其他细节(扩展 pip 卡住以防不兼容):
# Python version
Python 3.5.2
# Pytest version ( and plugins )
pytest==3.0.7
pytest-benchmark==3.1.0a2
pytest-catchlog==1.2.2
pytest-cov==2.4.0
pytest-ipdb==0.1.dev2
pytest-leaks==0.2.2
pytest-mock==1.6.0
pytest-rerunfailures==2.1.0
pytest-sugar==0.8.0
pytest-timeout==1.2.0
python-dateutil==2.6.0
python-dbusmock==0.16.7
# Pip Freeze ( Just in case )
alabaster==0.7.10
appdirs==1.4.3
argh==0.26.2
asn1crypto==0.22.0
astroid==1.5.2
Babel==2.4.0
bleach==2.0.0
bumpversion==0.5.3
cffi==1.10.0
click==6.7
click-plugins==1.0.3
colorama==0.3.7
colorlog==2.10.0
coverage==4.3.4
coveralls==1.1
cryptography==1.8.1
Cython==0.25.2
decorator==4.0.11
docopt==0.6.2
docutils==0.13.1
ecdsa==0.13
entrypoints==0.2.2
Fabric3==1.12.post1
fancycompleter==0.7
fields==5.0.0
flake8==3.3.0
flake8-docstrings==1.0.3
flake8-polyfill==1.0.1
freezegun==0.3.8
gnureadline==6.3.3
graphviz==0.6
html5lib==0.999999999
hunter==1.4.1
idna==2.5
imagesize==0.7.1
ipdb==0.10.2
ipykernel==4.6.1
ipython==6.0.0
ipython-genutils==0.2.0
ipywidgets==6.0.0
isort==4.2.5
jedi==0.10.2
Jinja2==2.9.6
jsonschema==2.6.0
jupyter==1.0.0
jupyter-client==5.0.1
jupyter-console==5.1.0
jupyter-core==4.3.0
lazy-object-proxy==1.2.2
MarkupSafe==1.0
mccabe==0.6.1
mistune==0.7.4
mock==2.0.0
mock-open==1.3.1
mypy-lang==0.4.6
nbconvert==5.1.1
nbformat==4.3.0
notebook==5.0.0
objgraph==3.1.0
ordereddict==1.1
packaging==16.8
pandocfilters==1.4.1
paramiko==1.18.2
pathtools==0.1.2
pbr==1.10.0
pdbpp==0.8.3
pexpect==4.2.1
pickleshare==0.7.4
pluggy==0.4.0
plumbum==1.6.3
prompt-toolkit==1.0.14
psutil==5.2.2
ptyprocess==0.5.1
py==1.4.33
py-cpuinfo==3.2.0
pyasn1==0.2.3
pycodestyle==2.3.1
pycparser==2.17
pycrypto==2.6.1
pydbus==0.6.0
pydocstyle==2.0.0
pyflakes==1.5.0
pygal==2.3.1
pygaljs==1.0.1
Pygments==2.2.0
pygobject==3.22.0
pylint==1.7.1
pyparsing==2.2.0
pystuck==0.8.5
pytest==3.0.7
pytest-benchmark==3.1.0a2
pytest-catchlog==1.2.2
pytest-cov==2.4.0
pytest-ipdb==0.1.dev2
pytest-leaks==0.2.2
pytest-mock==1.6.0
pytest-rerunfailures==2.1.0
pytest-sugar==0.8.0
pytest-timeout==1.2.0
python-dateutil==2.6.0
python-dbusmock==0.16.7
pytz==2017.2
PyYAML==3.12
pyzmq==16.0.2
qtconsole==4.3.0
requests==2.13.0
requests-mock==1.3.0
rpyc==3.3.0
-e git+git@github.com:bossjones/scarlett_os.git@c14ffcde608da12f5c2d4d9b81a63c7e618b3eed#egg=scarlett_os
simplegeneric==0.8.1
six==1.10.0
snowballstemmer==1.2.1
Sphinx==1.5.5
stevedore==1.18.0
termcolor==1.1.0
terminado==0.6
testpath==0.3
tornado==4.5.1
tox==2.7.0
traitlets==4.3.2
typing==3.6.1
virtualenv==15.0.3
virtualenv-clone==0.2.6
virtualenvwrapper==4.7.2
voluptuous==0.9.3
watchdog==0.8.3
wcwidth==0.1.7
webencodings==0.5.1
widgetsnbextension==2.0.0
wmctrl==0.3
wrapt==1.10.10
xdot==0.7
编辑:(还有一个细节,为什么我不只使用补丁上下文管理器或装饰器?)
pytest-mock
有一个很好的部分介绍了他们的设计选择,以及他们为什么决定放弃嵌套的 with
语句和装饰器。链接是here , 但为了以防万一,让我在这里提几个:
- excessive nesting of with statements breaking the flow of test
- receiving the mocks as parameters doesn't mix nicely with pytest's approach of naming fixtures as parameters, or pytest.mark.parametrize;
因此,如果可以使用此插件使我的代码更简洁一些,我愿意实现它。如果那不可能,那么也许我需要重新考虑一下。
最佳答案
您遇到的错误是被测代码命中了 AttributeError
而不是 TypeError
。
细节是假设某个对象有一个 .typename
成员,但它没有。
我想一旦你解决了这个谜题,剩下的就没问题了。
我看到有人打开了https://github.com/pytest-dev/pytest-mock/issues/84 (你?),让我们等待 pytest 开发人员对其进行分析,以防 2 个插件之间存在不兼容性。
关于Python3 + pytest + pytest 模拟 : Mocks leaking into other test functions breaking assertions?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43698734/
是否有效率偏好以下控制流选项之一用于循环或切换另一个? 选项 1: switch(...){ case 1: if (...) { ... } else if
我需要在某个地方修复一些 CSS,因为我的文本没有环绕,如果它是一个非常长的单词,它会无限期地继续下去。 在大多数情况下,我在我的 CSS 文件中尝试了 word-wrap: break-word;
这个问题在这里已经有了答案: What is the difference between "word-break: break-all" versus "word-wrap: break-word
我的问题: overflow-wrap: break-word 和 word-break: break-word 有区别吗? 非重复: 这里有一些现有的问题,乍一看可能是重复的,但实际上不是。 Wha
我目前想知道两者之间有什么区别。当我同时使用它们时,如果它不适合容器,它们似乎会打破这个词。但为什么 W3C 做了两种方式来做呢? 最佳答案 word-wrap: break-word 最近更改为 o
满足条件时如何跳出循环? 例如: for (i in 0..10){ if (i==3){ // equivalent of break } } 最佳答案 Q#没有中
CSS3 规范说部分支持 word-wrap:break-word; 在 Chrome 中你必须使用 word-wrap:break-all; 但是没有连字符。我正在使用 text-align:jus
我想在我的 View 列表中显示来自数据库的所有评论。但有时,评论会很长。我试图用 word-wrap:break-word 来“打破”它们,但没有结果——像这样的评论 aaaaaaaaaaaaaaa
我正在尝试将一个长 URL 放置在侧边栏中,以在表格单元格宽度的范围内中断和换行。我已将 style="word-break:break-all;" 添加到 td 和围绕文本和 URL 的 span
我有以下代码: public void post(String message) { final String mess = message; (new Thread() {
是否有 word-break: break-word 的 alternative 可以在 firefox 中使用? 在 firefox[版本 57.0] 中 在 Chrome [版本 62.0.320
在this question以及this blog ,其中提到了样式 word-break 及其值。此外,还有值 break-word 作为属于例如的东西。 自动换行类。 在最近的 VS 中 MVC
我正在尝试将文本包装在 td 中并使用以下样式 word-break:break-all 在 IE 中工作得很好,但在 Firefox 中失败,请注意这是不支持的!尝试了 http://petesbl
我正在使用“word-break: break-all”在任何字符之间插入分隔符。 但是,在 Chrome 中,它无法正常处理特定字符(例如冒号、分号、逗号),如下所示。 (我的代码笔在这里:http
它只有在我用不同的元素包裹 anchor 标记时才有效,但我正在阅读 html,所以我想将它添加为整个页面的样式。 最佳答案 我不确定你想在这里实现什么,如果你能分享一些代码片段会很好。 无论如何,我
这些看起来都是一样的,有什么区别? https://jsfiddle.net/pmuub8w1/2/ p{ word-break:normal; } p{
目前下面的代码,保持div宽度固定,换行由于break-all .Test{ float: left; margin-bottom: 2px; word-wrap:break-word; word-b
我正在使用 word-break: break-all; 并想知道如何让浏览器自动插入 hyphens ,如 MDN example 中所示. div { width: 80px; heigh
我的 html 有这种结构: content1 content2 content3 content4 content5 content6 co
我正在尝试对齐图像旁边的文本。我想考虑没有空格的长字符串。 我的css如下 .new_item { width: 100%; float: left; border-bottom: 1px solid
我是一名优秀的程序员,十分优秀!