Python 如何访问unittest.TestCase中的unittest.main(详细)设置

Python 如何访问unittest.TestCase中的unittest.main(详细)设置,python,unit-testing,Python,Unit Testing,根据文档,我可以在调用unittest.main时设置python单元测试的详细级别,例如 unittest.main(verbosity=2) 如何在unittest.TestCase中访问此信息?实现此目的的方法是在文件中对unittest.TestCase和unittest.main进行子类化。在这里,您定义了一个变量(例如,globalverb),该变量可以全局使用,也可以作为类或单例使用,然后重写unittest.main: def main(*args, **kwargs):

根据文档,我可以在调用
unittest.main
时设置python单元测试的详细级别,例如

unittest.main(verbosity=2)

如何在
unittest.TestCase
中访问此信息?

实现此目的的方法是在文件中对
unittest.TestCase
unittest.main
进行子类化。在这里,您定义了一个变量(例如,
globalverb
),该变量可以全局使用,也可以作为类或单例使用,然后重写
unittest.main

def main(*args, **kwargs):

    # parse arguments etc to get the verbosity number or whatever
    # ...
    # set this number to the defined class
    globalverb = verbose_number
    return unittest.main(*args, **kwargs)
稍后,您将子类化
unittest.TestCase

class MyTestCase(unittest.TestCase):
    def my_special_function(self):
        if globalverb ...
通过这种方法,可以从传递给unittest的参数中使用(派生的)TestCase中的verbose、verbosity或任何其他数字和信息


欢迎评论

我无法让Martjin Pieters的解决方案发挥作用,我想是因为unittest.main在初始化时运行测试,而其结果尚未分配给全局变量

相反,我将我的草签改为:

def new_parseArgs(self, argv): global old_parseArgs,verbosity old_parseArgs(self, argv) verbosity = self.verbosity if __name__ == '__main__': # monkeypatch unittest.TestProgram.parseArgs() to save verbosity # in a global variable old_parseArgs = unittest.TestProgram.parseArgs unittest.TestProgram.parseArgs = new_parseArgs unittest.main() def new_parseArgs(self,argv): 全局旧语法分析器,冗长 旧语法分析器args(self,argv) 冗长 如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu': #monkeypatch unittest.TestProgram.parseArgs()保存详细信息 #在全局变量中 old_parseArgs=unittest.TestProgram.parseArgs unittest.TestProgram.parseArgs=新的\u parseArgs unittest.main() 在需要了解详细情况的测试用例中,我使用了如下内容:

global verbosity ... if verbosity >= 2: print("Keys' order: %s" % dd.keys()) 全局冗长 ... 如果详细程度>=2: 打印(“密钥的顺序:%s”%dd.Keys())
任何基于修补或子类化
unittest.TestProgram
的方法的问题在于,必须在启动
unittest.TestProgram
之前将修补程序安装到位。但是,如果您的测试用例是通过发现运行的,那么这是不可能的:

python -m unittest discover -v
在发现案例中,一种有效的方法是使用模块向上搜索堆栈,直到找到
unittest.TestProgram
上的方法:

import inspect
import unittest

def unittest_verbosity():
    """Return the verbosity setting of the currently running unittest
    program, or 0 if none is running.

    """
    frame = inspect.currentframe()
    while frame:
        self = frame.f_locals.get('self')
        if isinstance(self, unittest.TestProgram):
            return self.verbosity
        frame = frame.f_back
    return 0

我的解决方案完全不同。我没有使用monkeypatching,而是利用了所有测试都是通过特制的启动脚本触发的优势。它收集了各种配置变量和环境设置,所以只需添加一个额外的导出就可以了

对于更一般的情况,创建test-runner.sh(或其他任何东西)可能是明智的解决方案,它将进行完全相同的shell调用,但在前面加上额外的导出前缀,而不是直接运行测试

因为一幅画抵得上千言万语:

这是我的测试跑步者:

#!/usr/bin/env bash

VERBOSE=false

while getopts ":vt:" opt; do
    case $opt in
        t)
            TEST_TO_RUN=$OPTARG
            ;;
        v)
            VERBOSE=true
            ;;
        \?)
          echo "Invalid option: -$OPTARG" >&2
          exit 1
          ;;
        :)
          echo "Option -$OPTARG requires an argument." >&2
          exit 1
      ;;
    esac
done

ENVS=""
ENVS+=" PYTHONPATH=$PYTHONPATH:$PWD"

PARAMS=""
PARAMS+=" -s --nologcapture --with-id"
PARAMS+=" --cov-config=.apirc --cov-report html --with-cov"

SERVER_PRIMER="coverage run --rcfile=.apirc"

if [[ ! -z "$TEST_TO_RUN" ]]; then
    PARAMS+=" $TEST_TO_RUN"
fi

if [[ "$VERBOSE" = true ]]; then
    PARAMS+=" -v"
    ENVS+=" TEST_VERBOSITY=2"
fi

eval "$ENVS nosetests $PARAMS"

RESULT_TEST=$?
然后我有了单元测试的方法:

@property
def verbosity(self):
    return int(os.environ.get('TEST_VERBOSITY', 0))
爬升堆栈,找到unittest.main()创建的“TestProgram”实例,并访问详细字段:

class MyTestCase(unittest.TestCase):

    def test_verbosity(self):
        """Return current verbosity"""
        for f in inspect.getouterframes(inspect.currentframe() ):
            args, _,_, local_dict = inspect.getargvalues(f[0])
            if args: 
                first_arg = args[0] 
                first_value = local_dict[first_arg]
                if type(first_value).__name__ == "TestProgram":
                    return first_value.verbosity

如果您只想访问
-v
选项,可以在测试中使用
self.\u resultForDoCleanups.showAll
(继承自
unittest.TestCase
)。如果为该测试调用了
-v
,则该字段为true。

如果始终从命令行运行,则只需解析来自
sys.argv
的参数即可。您可以手动执行(查找列表中出现的'-v'、'-vv'等),但我通常更喜欢在源代码中查找相关的解析器,并使用相同的版本(去掉伪选项)。在您的情况下,看起来是这样的:

相关代码似乎是。我们可以提取这段代码并获得以下内容:

    import argparse


    verbosity_parser = argparse.ArgumentParser(add_help=False)
    verbosity_parser.add_argument(
        '-v', '--verbose', dest='verbosity', 
        action='store_const', const=2,
        help='Verbose output')  # We could remove this if we want
    args, rest = verbosity_parser.parse_known_args()
    verbosity = args.verbosity
编辑 我刚刚意识到解析器是多么简单。我习惯于Django,那里有多个详细级别。在本例中,您可能只需检查
{'-v','-verbose'}&set(sys.argv)
或类似的内容

如果您还想处理
--quiet
标志,只需使用
argparse
方法,再次基于源代码,添加对
add_参数的另一个调用即可:

    parser.add_argument('-q', '--quiet', dest='verbosity',
                        action='store_const', const=0,
                        help='Quiet output')  # this could be removed
如果需要,我们还可以处理看似隐含的默认值:

    if verbosity is None:
        verbosity = 1

如果你总是从命令行运行,你可以直接解析
sys.argv
@DylanYoung:我建议你把它写下来作为一个答案。呵呵,我想这就是问题所在,哈哈。看起来OP想要通过编程来完成。不过,我喜欢您的帧遍历解决方案:)无论如何,答案现在就在那里: