如何使用 unittest 修复测试代码中被测模块的发现?
How to fix discovery of module-under-test in test code with unittest?
我一直在为这个错误而苦苦挣扎,我不知道为什么会这样。
ModuleNotFoundError: No module named 'lambdaFunction'
这是文件夹结构。
出于某种原因,当我尝试 运行 lambda_unit_test.py 时,它总是失败。
这是里面的代码:
import unittest
from lambdaFunction import index
class LambdaTest(unittest.TestCase):
def lambda_returns_Rick_Sanchez(self):
self.assertEquals(index.lambda_handlerx(), "Should return Rick Sanchez")
if __name__ == '__main__':
unittest.main()
我也试过 import lambdaFunction
之类的东西,但没有成功。
这些是命令行输出:
python3 -m unittest test.lambda_unit_test.py
E
======================================================================
ERROR: lambda_unit_test (unittest.loader._FailedTest)
----------------------------------------------------------------------
ImportError: Failed to import test module: lambda_unit_test
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/unittest/loader.py", line 154, in loadTestsFromName
module = __import__(module_name)
ModuleNotFoundError: No module named 'test.lambda_unit_test'
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
如果我从根文件夹尝试 运行ning python3 -m unittest test.lambda_unit_test
它不会 运行 任何测试:
python3 -m unittest test.lambda_unit_test
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
关于如何解决这个问题有什么想法吗?
import unittest
#the two lines below make anything located two levels above this file importable
import os.path, sys;
sys.path.append(os.path.join(os.path.abspath(__file__),*['..']*2))
from lambdaFunction import index
有2个问题。
问题 1
第一个问题 是“ModuleNotFoundError:没有名为 'lambdaFunction' 的模块”,这通常是由您如何正在 运行宁 unittest
。如 Running unittest with typical test directory structure (specifically, this nice answer 中所述),您必须确保 unittest
找到您的待测模块和测试文件。
所以,给定
myproject
├── lambdaFunction
│ ├── __init__.py
│ └── index.py
└── tests
├── __init__.py
└── lambda_unit_test.py
你运行unittest
在myproject
文件夹下:
$ cd myproject
$ python3 -m unittest discover
这会告诉 unittest
使用其 Test Discovery 功能来查找您的测试文件和测试方法。这将 也 自动修复你的导入路径 (sys.path
),这样你的测试就可以导入你的模块,而不需要你绕过 sys.path
。
如果发现工作正常,那么 from lambdaFunction import index
应该没问题,没有任何 ,这在重命名和移动文件和文件夹时很容易中断。
问题 2
第二个问题是命名,特别是测试文件的名称和测试方法的名称。它们不遵循测试发现中使用的 TestLoader.discover()
使用的默认模式:
lambda_unit_test.py
- 默认情况下,
unittest
查找与模式 test*.py
匹配的文件
- 至于为什么,请参阅 discover(start_dir, pattern='test*.py', top_level_dir=None) method of
unittest
's TestLoader class,它是“used to create test suites from classes and modules” .
lambda_returns_Rick_Sanchez
- 默认情况下,
unittest
查找以 test
开头的方法(例如 test_function
)。
- 至于为什么,请参阅testMethodPrefix attribute of
unittest
's TestLoader class,这是一个“字符串,给出了将被解释为测试方法的方法名称的前缀。默认值为'test'."
如果您按原样 运行 python3 -m unittest discover
,预计会得到“运行 0 次测试”。您可以 specify the exact test to run,跳过测试发现模式问题,通过传入 test_module.TestClass.test_method
:
$ python3 -m unittest test.lambda_unit_test.LambdaTest.lambda_returns_Rick_Sanchez
但这不是一个好的解决方案。解决此问题的一种方法是简单地遵循 Test Discovery 使用的默认模式。像这样重命名您的测试文件和测试方法:
lambda_unit_test.py
--> test_lambda_functions.py
lambda_returns_Rick_Sanchez
--> test_lambda_returns_Rick_Sanchez
$ python3 -m unittest discover -v
test_lambda_returns_Rick_Sanchez (test.test_lambda_functions.LambdaTest) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
如果您真的想要使用自定义测试文件名and/or测试方法名,您将不得不自定义测试加载器。请参阅文档的 load_tests Protocol 部分:
Modules or packages can customize how tests are loaded from them during normal test runs or test discovery by implementing a function called load_tests
.
有多种方法可以实现 load_tests
,一种方法是在 test/__init__.py
文件中添加一个 load_tests
函数,如 load_tests Protocol 中所述:
If discovery is started in a directory containing a package, either from the command line or by calling TestLoader.discover()
, then the package __init__.py
will be checked for load_tests
.
# In test/__init__.py
from pathlib import Path
from unittest import TestSuite
def load_tests(loader, tests, pattern):
suite = TestSuite()
loader.testMethodPrefix = 'lambda_returns'
tests = loader.discover(
Path(__file__).parent.as_posix(),
pattern='*_test.py',
)
suite.addTests(tests)
return suite
该代码将测试的方法名称前缀更改为 lambda_returns
并查找具有模式 *_test.py
的文件,两者都覆盖了默认行为。
有了它,它最终应该找到您的测试:
$ python3 -m unittest discover -v
lambda_returns_Rick_Sanchez (test.lambda_unit_test.LambdaTest) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
如果可以,我强烈建议您遵循测试文件和测试方法名称的默认模式。它越清晰(至少对我而言)并且需要维护的代码越少越好。
作为旁注,self.assertEquals
is now deprecated。您应该改用 assertEqual
.
我一直在为这个错误而苦苦挣扎,我不知道为什么会这样。
ModuleNotFoundError: No module named 'lambdaFunction'
这是文件夹结构。
出于某种原因,当我尝试 运行 lambda_unit_test.py 时,它总是失败。
这是里面的代码:
import unittest
from lambdaFunction import index
class LambdaTest(unittest.TestCase):
def lambda_returns_Rick_Sanchez(self):
self.assertEquals(index.lambda_handlerx(), "Should return Rick Sanchez")
if __name__ == '__main__':
unittest.main()
我也试过 import lambdaFunction
之类的东西,但没有成功。
这些是命令行输出:
python3 -m unittest test.lambda_unit_test.py
E
======================================================================
ERROR: lambda_unit_test (unittest.loader._FailedTest)
----------------------------------------------------------------------
ImportError: Failed to import test module: lambda_unit_test
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/unittest/loader.py", line 154, in loadTestsFromName
module = __import__(module_name)
ModuleNotFoundError: No module named 'test.lambda_unit_test'
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
如果我从根文件夹尝试 运行ning python3 -m unittest test.lambda_unit_test
它不会 运行 任何测试:
python3 -m unittest test.lambda_unit_test
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
关于如何解决这个问题有什么想法吗?
import unittest
#the two lines below make anything located two levels above this file importable
import os.path, sys;
sys.path.append(os.path.join(os.path.abspath(__file__),*['..']*2))
from lambdaFunction import index
有2个问题。
问题 1
第一个问题 是“ModuleNotFoundError:没有名为 'lambdaFunction' 的模块”,这通常是由您如何正在 运行宁 unittest
。如 Running unittest with typical test directory structure (specifically, this nice answer 中所述),您必须确保 unittest
找到您的待测模块和测试文件。
所以,给定
myproject
├── lambdaFunction
│ ├── __init__.py
│ └── index.py
└── tests
├── __init__.py
└── lambda_unit_test.py
你运行unittest
在myproject
文件夹下:
$ cd myproject
$ python3 -m unittest discover
这会告诉 unittest
使用其 Test Discovery 功能来查找您的测试文件和测试方法。这将 也 自动修复你的导入路径 (sys.path
),这样你的测试就可以导入你的模块,而不需要你绕过 sys.path
。
如果发现工作正常,那么 from lambdaFunction import index
应该没问题,没有任何
问题 2
第二个问题是命名,特别是测试文件的名称和测试方法的名称。它们不遵循测试发现中使用的 TestLoader.discover()
使用的默认模式:
lambda_unit_test.py
- 默认情况下,
unittest
查找与模式test*.py
匹配的文件
- 至于为什么,请参阅 discover(start_dir, pattern='test*.py', top_level_dir=None) method of
unittest
's TestLoader class,它是“used to create test suites from classes and modules” .
- 默认情况下,
lambda_returns_Rick_Sanchez
- 默认情况下,
unittest
查找以test
开头的方法(例如test_function
)。 - 至于为什么,请参阅testMethodPrefix attribute of
unittest
's TestLoader class,这是一个“字符串,给出了将被解释为测试方法的方法名称的前缀。默认值为'test'."
- 默认情况下,
如果您按原样 运行 python3 -m unittest discover
,预计会得到“运行 0 次测试”。您可以 specify the exact test to run,跳过测试发现模式问题,通过传入 test_module.TestClass.test_method
:
$ python3 -m unittest test.lambda_unit_test.LambdaTest.lambda_returns_Rick_Sanchez
但这不是一个好的解决方案。解决此问题的一种方法是简单地遵循 Test Discovery 使用的默认模式。像这样重命名您的测试文件和测试方法:
lambda_unit_test.py
-->test_lambda_functions.py
lambda_returns_Rick_Sanchez
-->test_lambda_returns_Rick_Sanchez
$ python3 -m unittest discover -v
test_lambda_returns_Rick_Sanchez (test.test_lambda_functions.LambdaTest) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
如果您真的想要使用自定义测试文件名and/or测试方法名,您将不得不自定义测试加载器。请参阅文档的 load_tests Protocol 部分:
Modules or packages can customize how tests are loaded from them during normal test runs or test discovery by implementing a function called
load_tests
.
有多种方法可以实现 load_tests
,一种方法是在 test/__init__.py
文件中添加一个 load_tests
函数,如 load_tests Protocol 中所述:
If discovery is started in a directory containing a package, either from the command line or by calling
TestLoader.discover()
, then the package__init__.py
will be checked forload_tests
.
# In test/__init__.py
from pathlib import Path
from unittest import TestSuite
def load_tests(loader, tests, pattern):
suite = TestSuite()
loader.testMethodPrefix = 'lambda_returns'
tests = loader.discover(
Path(__file__).parent.as_posix(),
pattern='*_test.py',
)
suite.addTests(tests)
return suite
该代码将测试的方法名称前缀更改为 lambda_returns
并查找具有模式 *_test.py
的文件,两者都覆盖了默认行为。
有了它,它最终应该找到您的测试:
$ python3 -m unittest discover -v
lambda_returns_Rick_Sanchez (test.lambda_unit_test.LambdaTest) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
如果可以,我强烈建议您遵循测试文件和测试方法名称的默认模式。它越清晰(至少对我而言)并且需要维护的代码越少越好。
作为旁注,self.assertEquals
is now deprecated。您应该改用 assertEqual
.