我有一个包含Python单元测试的目录。每个单元测试模块的格式是test_*.py。我正在尝试创建一个名为all_test.py的文件,您猜对了,它将以上述测试形式运行所有文件并返回结果。到目前为止,我尝试了两种方法;两者都失败了。我将展示这两种方法,我希望有人知道如何正确地做到这一点。
对于我的第一次勇敢的尝试,我想“如果我只是导入文件中的所有测试模块,然后调用这个unittest.main() doodad,它就会工作,对吗?”事实证明我错了。
import glob
import unittest
testSuite = unittest.TestSuite()
test_file_strings = glob.glob('test_*.py')
module_strings = [str[0:len(str)-3] for str in test_file_strings]
if __name__ == "__main__":
unittest.main()
这并没有起作用,我得到的结果是:
$ python all_test.py
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
对于我的第二次尝试,我想,好吧,也许我将尝试以一种更“手动”的方式来完成整个测试。所以我尝试如下:
import glob
import unittest
testSuite = unittest.TestSuite()
test_file_strings = glob.glob('test_*.py')
module_strings = [str[0:len(str)-3] for str in test_file_strings]
[__import__(str) for str in module_strings]
suites = [unittest.TestLoader().loadTestsFromName(str) for str in module_strings]
[testSuite.addTest(suite) for suite in suites]
print testSuite
result = unittest.TestResult()
testSuite.run(result)
print result
#Ok, at this point I have a result
#How do I display it as the normal unit test command line output?
if __name__ == "__main__":
unittest.main()
这也没有工作,但它似乎如此接近!
$ python all_test.py
<unittest.TestSuite tests=[<unittest.TestSuite tests=[<unittest.TestSuite tests=[<test_main.TestMain testMethod=test_respondes_to_get>]>]>]>
<unittest.TestResult run=1 errors=0 failures=0>
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
我似乎有一个某种类型的套件,我可以执行结果。我有点担心这个事实,它说我只运行=1,似乎应该运行=2,但它是进步。但是我如何传递和显示结果的主要?或者说,我怎样才能让它工作,从而运行这个文件,并运行这个目录下的所有单元测试?
你可以用一个测试者来帮你做这件事。鼻子就是个很好的例子。运行时,它将在当前树中找到测试并运行它们。
更新:
这是我在没有鼻子之前写的一些代码。您可能不想要显式的模块名称列表,但其余的可能对您有用。
testmodules = [
'cogapp.test_makefiles',
'cogapp.test_whiteutils',
'cogapp.test_cogapp',
]
suite = unittest.TestSuite()
for t in testmodules:
try:
# If the module defines a suite() function, call it to get the suite.
mod = __import__(t, globals(), locals(), ['suite'])
suitefn = getattr(mod, 'suite')
suite.addTest(suitefn())
except (ImportError, AttributeError):
# else, just load all the test cases from the module.
suite.addTest(unittest.defaultTestLoader.loadTestsFromName(t))
unittest.TextTestRunner().run(suite)
这个BASH脚本将从文件系统中的任意位置执行python unittest test目录,无论您在哪个工作目录中:它的工作目录总是位于测试目录的位置。
所有测试,独立的$PWD
unittest Python模块对当前目录敏感,除非你告诉它在哪里(使用discover -s选项)。
当你在。/src或。/example工作目录下,并且你需要一个快速的整体单元测试时,这是很有用的:
#!/bin/bash
this_program="$0"
dirname="`dirname $this_program`"
readlink="`readlink -e $dirname`"
python -m unittest discover -s "$readlink"/test -v
选定的测试,独立的$PWD
我将这个实用程序文件命名为runone.py,并像这样使用它:
runone.py <test-python-filename-minus-dot-py-fileextension>
#!/bin/bash
this_program="$0"
dirname="`dirname $this_program`"
readlink="`readlink -e $dirname`"
(cd "$dirname"/test; python -m unittest $1)
在生产过程中,不需要test/__init__.py文件来增加包/内存开销。
使用Python 2.7及更高版本时,你不需要编写新代码或使用第三方工具来完成这项工作;通过命令行执行递归测试是内置的。在你的测试目录中放入__init__.py,然后:
python -m unittest discover <test_directory>
# or
python -m unittest discover -s <directory> -p '*_test.py'
你可以在python 2.7中阅读更多内容
或者是python。X单元测试文档。
2021年更新:
许多现代python项目使用更高级的工具,如pytest。例如,下拉matplotlib或scikit-learn,您将看到它们都在使用它。
了解这些新工具非常重要,因为当您有超过7000个测试时,您需要:
更高级的方法来总结通过、跳过、警告和错误的内容
很容易看出他们是如何失败的
运行时的完成百分比
总运行时间
生成测试报告的方法
等等
我没有包,如本页所述,这是在发布发现时产生的问题。所以,我使用了下面的解决方案。所有测试结果都将放在给定的输出文件夹中。
RunAllUT.py:
"""
The given script is executing all the Unit Test of the project stored at the
path %relativePath2Src% currently fixed coded for the given project.
Prerequired:
- Anaconda should be install
- For the current user, an enviornment called "mtToolsEnv" should exists
- xmlrunner Library should be installed
"""
import sys
import os
import xmlrunner
from Repository import repository
relativePath2Src="./../.."
pythonPath=r'"C:\Users\%USERNAME%\.conda\envs\YourConfig\python.exe"'
outputTestReportFolder=os.path.dirname(os.path.abspath(__file__))+r'\test-reports' #subfolder in current file path
class UTTesting():
"""
Class tto run all the UT of the project
"""
def __init__(self):
"""
Initiate instance
Returns
-------
None.
"""
self.projectRepository = repository()
self.UTfile = [] #List all file
def retrieveAllUT(self):
"""
Generate the list of UT file in the project
Returns
-------
None.
"""
print(os.path.realpath(relativePath2Src))
self.projectRepository.retriveAllFilePaths(relativePath2Src)
#self.projectRepository.printAllFile() #debug
for file2scan in self.projectRepository.devfile:
if file2scan.endswith("_UT.py"):
self.UTfile.append(file2scan)
print(self.projectRepository.devfilepath[file2scan]+'/'+file2scan)
def runUT(self,UTtoRun):
"""
Run a single UT
Parameters
----------
UTtoRun : String
File Name of the UT
Returns
-------
None.
"""
print(UTtoRun)
if UTtoRun in self.projectRepository.devfilepath:
UTtoRunFolderPath=os.path.realpath(os.path.join(self.projectRepository.devfilepath[UTtoRun]))
UTtoRunPath = os.path.join(UTtoRunFolderPath, UTtoRun)
print(UTtoRunPath)
#set the correct execution context & run the test
os.system(" cd " + UTtoRunFolderPath + \
" & " + pythonPath + " " + UTtoRunPath + " " + outputTestReportFolder )
def runAllUT(self):
"""
Run all the UT contained in self
The function "retrieveAllUT" sjould ahve been performed before
Returns
-------
None.
"""
for UTfile in self.UTfile:
self.runUT(UTfile)
if __name__ == "__main__":
undertest=UTTesting()
undertest.retrieveAllUT()
undertest.runAllUT()
在我的特定项目中,我有一个在其他脚本中使用的类。对于您的用例来说,这可能有点过头了。
Repository.py
import os
class repository():
"""
Class that decribed folder and file in a repository
"""
def __init__(self):
"""
Initiate instance
Returns
-------
None.
"""
self.devfile = [] #List all file
self.devfilepath = {} #List all file paths
def retriveAllFilePaths(self,pathrepo):
"""
Retrive all files and their path in the class
Parameters
----------
pathrepo : Path used for the parsin
Returns
-------
None.
"""
for path, subdirs, files in os.walk(pathrepo):
for file_name in files:
self.devfile.append(file_name)
self.devfilepath[file_name] = path
def printAllFile(self):
"""
Display all file with paths
Parameters
----------
def printAllFile : TYPE
DESCRIPTION.
Returns
-------
None.
"""
for file_loop in self.devfile:
print(self.devfilepath[file_loop]+'/'+file_loop)
在你的测试文件中,你需要有一个像这样的main:
if __name__ == "__main__":
import xmlrunner
import sys
if len(sys.argv) > 1:
outputFolder = sys.argv.pop() #avoid conflic with unittest.main
else:
outputFolder = r'test-reports'
print("Report will be created and store there: " + outputFolder)
unittest.main(testRunner=xmlrunner.XMLTestRunner(output=outputFolder))