一段 Python 代码如何判断是否在 unittest 下运行

42

我有一个使用Python unittest模块进行单元测试的大型项目。

我有一个控制系统大部分行为的小方法。当在UTs下运行时,我需要这个方法返回固定的结果,以便进行一致的测试运行,但是对于每个单独的UT来说,模拟这个方法会很昂贵。

是否有一种方式可以使这个单独的方法成为unittest感知的,以便在运行unittest时修改其行为?


另请参见https://dev59.com/AG855IYBdhLWcg3w5IvZ#7651002 - djvg
6个回答

26

如果要检查unittest模块是否已加载,只有在运行测试时才应该加载。

>>> 'unittest' in sys.modules.keys()
False
>>> from unittest import TestCase
>>> 'unittest' in sys.modules.keys()
True

4
如果您跳过.keys(),直接使用'unittest' in sys.modules会更有效率。 - Troy
不幸的是,这在Spyder中不起作用(刚刚发现有一堆模块始终预加载)。 - CAPSLOCK
这是我确定用户在访问共享模块时是否正在使用 behavepytest 运行测试的解决方案。 - Eitel Dagnin

11

我的解决方案是在运行 unittest 前设置一个TEST_FLAG=true的环境变量。例如:

TEST_FLAG=true python -m unittest discover -s tests -b

那么,只需要检查变量是否已设置。例如:
MONGODB_URI =
    os.environ.get('MONGODB_URI') if not os.environ.get('TEST_FLAG') 
        else os.environ.get('MONGODB_TEST_URI')

7

我不太了解 unittest 模块,但如果您正在运行文件进行单元测试,则可以使用以下 if 语句将测试代码封装起来:

if __name__ == "__main__":

任何位于if语句中的代码,只有在你的特定模块被直接调用时才会执行,而不是被导入到其他地方。根据文档,这就是你应该首先调用unittest.main()的方式。https://docs.python.org/2/library/unittest.html 这假设你没有从命令行运行。
编辑:您可以查看函数堆栈,尝试找到unittest.main()函数。
import inspect

def in_unit_test():
  current_stack = inspect.stack()
  for stack_frame in current_stack:
    for program_line in stack_frame[4]:    # This element of the stack frame contains 
      if "unittest" in program_line:       # some contextual program lines
        return True
  return False

这是一种比较巧妙的解决方案,但是inspect模块有很多用于内省的实用函数。请参考https://docs.python.org/2/library/inspect.html

我的解决方案是在上面的“if name ...”行之后创建一个标志,“sys.unittesting = None”。sys被导入到很多文件中...当然,任何常用的导入模块都可以。我发现有时确实需要找出是否正在进行单元测试,例如抑制等待用户输入的事情。 - mike rodent
2
警告:此函数将始终返回True,因为函数名为in_unittest,并将由if“unittest”in program_line:断言。 - EwyynTomato
1
糟糕,已修复。谢谢。 - TheSoundDefense

3

使用 tox 我可以像这样设置环境变量:

[testenv]
setenv = TOX_TESTENV = true

然后在代码中,我检查变量是否已设置:

import os


if os.env.get('TOX_TESTENV'):
    # Code is running under test.
    # This is useful to configure log levels for example.

1
您可以在运行时为测试修改函数。例如:

module.py

def func():
    return random.randint()

test.py

import module

def replacement_func():
    return 4 # chosen by fair dice roll

module.func = replacement_func

# run unit tests here

现在,无论何时module中的代码调用func()函数,它实际上将会回调到您的replacement_func()函数。

1
我相信还有其他更好的方法,但你可以在主代码中设置一个全局标志,而不是在单元测试中设置,然后在你的方法中访问它。当然,另一种方法是在单元测试设置中重写该方法 - 如果你的方法名为,并且你有一个,那么在测试前设置就可以完成工作,你可能需要将模块名称放入前面的语句中

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接