kjo*_*kjo 7 python testing unit-testing project
是否可以使用如下文件结构实现Python项目?:
myproj
??? a.py
??? b.py
??? c.py
??? test/
??? a.py
??? b.py
??? c.py
Run Code Online (Sandbox Code Playgroud)
特别要注意,下面的测试脚本test/
与它们正在测试的模块文件具有相同的基本名称 1.(换句话说,test/a.py
包含单元测试a.py
; test/b.py
包含那些b.py
等等)
test/
所有导入下的测试unittest
和定义的子类unittest.TestCase
.
我想知道如何在test/
单独和一起运行测试.
我尝试了很多变种python -m unittest ...
,但它们都失败了(下面的例子),或者最终运行零测试.
例如,
% python -m unittest test.a
Traceback (most recent call last):
File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main
"__main__", fname, loader, pkg_name)
File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
exec code in run_globals
File "/usr/lib/python2.7/unittest/__main__.py", line 12, in <module>
main(module=None)
File "/usr/lib/python2.7/unittest/main.py", line 94, in __init__
self.parseArgs(argv)
File "/usr/lib/python2.7/unittest/main.py", line 149, in parseArgs
self.createTests()
File "/usr/lib/python2.7/unittest/main.py", line 158, in createTests
self.module)
File "/usr/lib/python2.7/unittest/loader.py", line 130, in loadTestsFromNames
suites = [self.loadTestsFromName(name, module) for name in names]
File "/usr/lib/python2.7/unittest/loader.py", line 100, in loadTestsFromName
parent, obj = obj, getattr(obj, part)
AttributeError: 'module' object has no attribute 'a'
Run Code Online (Sandbox Code Playgroud)
如果我将test/
目录的名称更改为t/
,则错误变为:
% python -m unittest t.a
Traceback (most recent call last):
File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main
"__main__", fname, loader, pkg_name)
File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
exec code in run_globals
File "/usr/lib/python2.7/unittest/__main__.py", line 12, in <module>
main(module=None)
File "/usr/lib/python2.7/unittest/main.py", line 94, in __init__
self.parseArgs(argv)
File "/usr/lib/python2.7/unittest/main.py", line 149, in parseArgs
self.createTests()
File "/usr/lib/python2.7/unittest/main.py", line 158, in createTests
self.module)
File "/usr/lib/python2.7/unittest/loader.py", line 130, in loadTestsFromNames
suites = [self.loadTestsFromName(name, module) for name in names]
File "/usr/lib/python2.7/unittest/loader.py", line 91, in loadTestsFromName
module = __import__('.'.join(parts_copy))
ImportError: No module named t
Run Code Online (Sandbox Code Playgroud)
要么
% python -m unittest t/a.py
Traceback (most recent call last):
File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main
"__main__", fname, loader, pkg_name)
File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
exec code in run_globals
File "/usr/lib/python2.7/unittest/__main__.py", line 12, in <module>
main(module=None)
File "/usr/lib/python2.7/unittest/main.py", line 94, in __init__
self.parseArgs(argv)
File "/usr/lib/python2.7/unittest/main.py", line 149, in parseArgs
self.createTests()
File "/usr/lib/python2.7/unittest/main.py", line 158, in createTests
self.module)
File "/usr/lib/python2.7/unittest/loader.py", line 130, in loadTestsFromNames
suites = [self.loadTestsFromName(name, module) for name in names]
File "/usr/lib/python2.7/unittest/loader.py", line 91, in loadTestsFromName
module = __import__('.'.join(parts_copy))
ImportError: Import by filename is not supported.
Run Code Online (Sandbox Code Playgroud)
(我使用的是Python 2.7.9.)
UPDATE
由于我对这个问题给予了赏识,我将非常明确地说明什么是可接受的答案.
以下任一项都是可以接受的:
如何从命令行调用unittest
以运行单个测试或test/
目录下的所有测试; 解决方案可以接受对测试脚本中的代码进行小的更改(例如对import语句的修改).
如果出于某种原因无法实现上述文件结构,则详细说明将是可接受的解决方案.
作为基本案例,从以下最小案例开始,使用以下文件结构:
myproj
??? a.py
??? b.py
??? test/
??? a.py
??? b.py
Run Code Online (Sandbox Code Playgroud)
......以及以下内容
# a.py
def hello():
print 'hello world'
Run Code Online (Sandbox Code Playgroud)
# b.py
def bye():
print 'good-bye world'
Run Code Online (Sandbox Code Playgroud)
# test/a.py
import unittest
import a
class TestA(unittest.TestCase):
def test_hello(self):
self.assertEqual(a.hello(), None)
Run Code Online (Sandbox Code Playgroud)
# test/b.py
import unittest
import b
class TestB(unittest.TestCase):
def test_bye(self):
self.assertEqual(b.bye(), None)
Run Code Online (Sandbox Code Playgroud)
展示如何告诉unittest
您运行测试test/a.py
,以及如何运行"所有测试test
".(后者应该继续工作,即使添加了新的测试脚本test
,或者删除了一些当前的测试脚本.)
迄今为止提供的建议的最小测试表明它们不起作用.例如:
% python -m unittest discover -s test -p '*.py'
EE
======================================================================
ERROR: test_hello (a.TestA)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/SHIVAMJINDAL/myproj/test/a.py", line 6, in test_hello
self.assertEqual(a.hello(), None)
AttributeError: 'module' object has no attribute 'hello'
======================================================================
ERROR: test_bye (b.TestB)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/SHIVAMJINDAL/myproj/test/b.py", line 6, in test_bye
self.assertEqual(b.bye, None)
AttributeError: 'module' object has no attribute 'bye'
----------------------------------------------------------------------
Ran 2 tests in 0.000s
FAILED (errors=2)
% tree .
.
??? a.py
??? b.py
??? __init__.py
??? test/
??? a.py
??? b.py
??? __init__.py
1 directory, 6 files
Run Code Online (Sandbox Code Playgroud)
1这种约束是非常有意的,它是这里提出的问题的一个组成部分.(IOW,需要放松这种约束的"解决方案"实际上不是解决方案.)
我能够使您的方法有效,但几乎没有必要和强制性的更改.
__init__.py
所以下面是我的树形结构
root@5db7ad85dafd:/project# tree
.
__init__.py
a.py
test
__init__.py
a.py
1 directory, 4 files
root@5db7ad85dafd:/project# python --version
Python 2.7.9
Run Code Online (Sandbox Code Playgroud)
项目/ a.py
hello = 'tarun'
Run Code Online (Sandbox Code Playgroud)
项目/测试/ a.py
import unittest
from .. import a
class TestStringMethods(unittest.TestCase):
def test_abc(self):
assert a.hello == "tarun"
Run Code Online (Sandbox Code Playgroud)
注意from .. import a
哪个是导入的
接下来,我们将测试放在项目的根文件夹中,如下所示
root@5db7ad85dafd:/project# python -m unittest discover -t .. -s test -p "*.py"
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Run Code Online (Sandbox Code Playgroud)
-t
这里设置了顶级导入目录,所以我们的相对导入可以
-s
告诉我们测试所在的目录-p
告诉应该在
哪个模式中发现测试
当您想要进行单独的测试时,您将执行以下操作
python -m unittest discover -t .. -s test -p "a.py"
Run Code Online (Sandbox Code Playgroud)
要么
python -m unittest discover -t .. -s test -p "*.py" a
Run Code Online (Sandbox Code Playgroud)
图片总是比文字更有价值
编辑-1
在看到Peter的回答之后想要更新我的回答.我没有提到从固定命名包导入的原因是,这意味着您需要知道克隆代码的文件夹的名称,并强制保持相同.但是如果你仍然想要采用这种方法,那么一种方法是将实际移动到子文件夹中
所以它会repo/project/test/a.py
在您的测试中使用
from project import a
Run Code Online (Sandbox Code Playgroud)
然后从repo文件夹中运行它,如下所示
root@5db7ad85dafd:/repo# python -m unittest discover -v -t project -s project.test -p "*.py"
test_abc (test.a.TestStringMethods) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Run Code Online (Sandbox Code Playgroud)
或者像下面的测试文件夹一样
root@5db7ad85dafd:/repo/project# python -m unittest discover -v -t .. -s test -p "*.py"
test_abc (project.test.a.TestStringMethods) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Run Code Online (Sandbox Code Playgroud)
在这种情况下,将项目文件夹从根目录移动一级,将确保项目名称不依赖于克隆项目的文件夹
__init__.py
看来你的 python 包 myproj 和 test 下没有文件。那就是您无法在测试中导入模块。
__init__.py
请在 test 和 myproj 目录中添加空白文件。如果这不能解决问题,请提供任何测试文件的代码。
您在 test/b.py 文件中使用了 import b,但它应该是 from myproj import b。因为如果您仅使用 import b ,它将导入当前文件(您在其中编写了测试并且该文件没有任何 bye() 方法)。因此,您可以更改测试文件的文件名或使用以下代码。
# test/b.py
import unittest
from myproj import b
class TestB(unittest.TestCase):
def test_bye(self):
self.assertEqual(b.bye(), None)
Run Code Online (Sandbox Code Playgroud)