1. 程式人生 > 實用技巧 >【讀原始碼】Unittest -- __init__.py 和 __main__.py

【讀原始碼】Unittest -- __init__.py 和 __main__.py

目錄

__init__.py

__all__ = ['TestResult', 'TestCase', 'TestSuite',
           'TextTestRunner', 'TestLoader', 'FunctionTestCase', 'main',
           'defaultTestLoader', 'SkipTest', 'skip', 'skipIf', 'skipUnless',
           'expectedFailure', 'TextTestResult', 'installHandler',
           'registerResult', 'removeResult', 'removeHandler']

# Expose obsolete functions for backwards compatibility
__all__.extend(['getTestCaseNames', 'makeSuite', 'findTestCases'])

__unittest = True

from .result import TestResult
from .case import (TestCase, FunctionTestCase, SkipTest, skip, skipIf,
                   skipUnless, expectedFailure)
from .suite import BaseTestSuite, TestSuite
from .loader import (TestLoader, defaultTestLoader, makeSuite, getTestCaseNames,
                     findTestCases)
from .main import TestProgram, main
from .runner import TextTestRunner, TextTestResult
from .signals import installHandler, registerResult, removeResult, removeHandler

# deprecated
_TextTestResult = TextTestResult

# There are no tests here, so don't try to run anything discovered from
# introspecting the symbols (e.g. FunctionTestCase). Instead, all our
# tests come from within unittest.test.
def load_tests(loader, tests, pattern):
    import os.path
    # top level directory cached on loader instance
    this_dir = os.path.dirname(__file__)
    return loader.discover(start_dir=this_dir, pattern=pattern)

__init__.py 特殊檔案的作用

__init__.py 檔案的存在使得 unittest 的目錄被 Python 直譯器當做一個包 (Package)。

__all__ 特殊變數的作用

__all__ 變數定義適用匯入語句 from unittest import * 時,會匯入到當前名稱空間裡的東西。

相對匯入

from .xxx import xxx 使用相對匯入從子模組中變數、類或函式等

其他

load_tests 定義一個函式,從 init.py 所在的目錄適用 loader 模組的 discover 函式發現用例

__main__.py

"""Main entry point"""

import sys
if sys.argv[0].endswith("__main__.py"):
    import os.path
    # We change sys.argv[0] to make help message more useful
    # use executable without path, unquoted
    # (it's just a hint anyway)
    # (if you have spaces in your executable you get what you deserve!)
    executable = os.path.basename(sys.executable)
    sys.argv[0] = executable + " -m unittest"
    del os
    print(sys.argv[0])

__unittest = True

from .main import main, TestProgram

main(module=None)

__main__.py 特殊檔案的作用

python -m unittest xxx 執行 unittest 時,__main__.py 會被執行

其他

python -m unittest xxx 執行 unittest 時,sys.argv 變數是個列表,內容是類似 ['/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/__main__.py', 'main.py']。sys.executable 是 Python 直譯器的可執行檔案的名字也就是 python

if 邏輯修改了 sys.argv[0] 的內容變成了 python -m unittest

。目的是簡化了資訊。

然後使用相對匯入,匯入了 main、TestProgram,從 main.py 中看到 main=TestProgram,即 main 變數等同於 TestProgram 類。然後呼叫 main(module=None) 即執行 TestProgram 的例項初始化 __init__() 方法,因此, TestProram.init 方法定義了主要的執行流程。