簡體   English   中英

如何訪問 unittest.TestCase 中的 unittest.main(verbosity) 設置

[英]how to access the unittest.main(verbosity) setting in a unittest.TestCase

根據文檔,我可以在調用unittest.main時設置 python unittest 的詳細級別,例如

unittest.main(verbosity=2)

如何在unittest.TestCase中訪問此信息?

任何基於修補或子類化unittest.TestProgram的方法的問題在於,您必須在啟動unittest.TestProgram之前將補丁安裝到位。 但如果您的測試用例是通過發現運行的,那將是不可能的:

python -m unittest discover -v

在發現案例中有效的一種方法是使用inspect模塊搜索堆棧,直到找到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

實現此目的的一種方法是在文件中子類unittest.TestCaseunittest.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 ...

通過這種方法,可以在(派生的)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()

在需要知道詳細程度的測試用例中,我使用類似的東西:

            global verbosity

    ...

            if verbosity >= 2:
                print("Keys' order: %s" % dd.keys())

我的解決方案完全不同。 我沒有使用 monkeypatching,而是利用我所有的測試都是通過特制的啟動腳本觸發的。 它收集各種配置變量和設置環境,因此只需添加一個額外的導出就非常簡單。

對於更一般的情況,這可能是明智的解決方案,而不是直接運行測試,而是創建 test-runner.sh(或其他),它將進行完全相同的 shell 調用,但帶有額外的 export 前綴。

因為一圖勝千言:

這是我的測試跑步者:

#!/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._resultForDoCleanups.showAll檢查它(繼承自unittest.TestCase )。 如果為該測試調用-v ,則該字段為真。

如果你總是從命令行運行,你可以只解析來自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_argument的調用,再次基於源代碼:

    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

這僅在通過命令行開關設置詳細程度時有效。

我將以下內容放在test.py文件的頂部:

verbose = sum(arg.count('v')
for arg in sys.argv if arg.startswith("-") and not arg.startswith("--"))

在其他地方,在代碼中我可以檢查verbose的值並相應地進行跟蹤。 例子:

if verbose > 2:
  sys.stderr.write("Some very noisy message\n")
  sys.stderr.flush()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM