如何在python中对以下代码进行模拟/单元测试?

时间:2019-07-26 00:54:59

标签: python unit-testing

如何对以下内容进行单元测试?

def sigterm_handler(signum, frame):
    pid = os.getpid()  # type: int
    sys.exit(0)

signal.signal(signal.SIGTERM, sigterm_handler)

我应该模拟并确保模拟被调用吗?

3 个答案:

答案 0 :(得分:2)

我会编写一个在子进程中运行您的代码的测试,以检查您是否成功终止了

例如,假设您的问题代码存在于名为signals.py的模块中。您可以编写一个如下所示的测试包装器模块:

test_signals_wrapper.py

from time import sleep
from sys import exit

# import this last to ensure it overrides any prior settings
import signals

while True:
    sleep(1)

exit(1)  # just in case the loop ends for other reasons

现在您可以编写如下所示的单元测试:

test_signals.py

from subprocess import run, TimeoutExpired
from sys import executable

def test_sigterm_handler():
    try:
        status = run([executable, '-m', 'test_signals_wrapper'], timeout=30)
    except TimeoutExpired:
        assert False, 'Did not trigger assertion in 30 seconds'

    assert status.returncode == 0, f'Wrong return code: {status.returncode}'

这需要一些额外的基础架构来进行测试,但是它解决了测试此代码的所有问题。通过在子进程中运行,您可以自由执行sys.exit并获取返回值。通过具有包装器脚本,您可以控制代码的加载和运行方式。您无需模拟任何事情,只需确保正确设置了程序包,并且测试运行程序没有尝试将包装脚本用作测试。

答案 1 :(得分:1)

猴子修补处理程序并在测试时发送信号吗?

import os
import signal
import sys
import time

# your handler
def sigterm_handler(signum, frame):
    print("Handled")
    pid = os.getpid()  # type: int  FIXME: what's this for?
    sys.exit(0)

signal.signal(signal.SIGTERM, sigterm_handler)

# Mock out the existing sigterm_handler
_handled = False
def mocked_sigterm_handler(signum, frame):
    print("Mocked")
    _handled = True

# register the handler
signal.signal(signal.SIGTERM, mocked_sigterm_handler)

# test sending the signal
os.kill(os.getpid(), signal.SIGTERM)
print(f"done ({_handled})")

# reset your handler?
signal.signal(signal.SIGTERM, sigterm_handler)

如果您想测试处理程序本身,则可能必须在这样的处理程序中放置一些类似这样的代码。

if _unittesting_sigterm_handler:
    _handled = True
else:
    sys.exit(0)

然后您可以直接调用处理程序(或在调用中通过测试标志)。

_unittesting_sigterm_handler = True
sigterm_handler(0, None)

答案 2 :(得分:0)

您显示的代码行不适合进行单元测试,而应该进行集成测试。原因是,您的代码行仅包含与其他组件(在这种情况下为signalsysos模块的交互)组成。

因此,您可能会遇到的错误在于与这些其他组件的交互:您是否在正确的组件中调用正确的函数,并以正确的顺序为参数提供正确的值,并且是您的结果/反应希望他们是?

所有这些问题都无法在单元测试中回答,在那里应该找到可以在隔离的单元中找到的错误:如果嘲笑signalsys和/或{ {1}}依赖性,然后您将编写模拟,以使其反映您对这些组件的理解(可能是错误的)。因此,尽管集成系统中的代码可能会失败,但单元测试将成功。如果您的目的是使代码在不同的系统上工作,那么您甚至可能会遇到这样的情况,即代码在一个集成中(也许是Linux)可以工作,而在另一个集成中(可能是Windows)却无法工作。

因此,对于像您这样的代码,单元测试以及因此进行单元测试的模拟没有太大价值。