如何为bin目录中的脚本编写Python单元测试
Python如何为bin目录中的脚本编写Python单元测试,python,unit-testing,python-unittest,Python,Unit Testing,Python Unittest,Pythonunittest模块似乎为项目假设了一个目录结构,其中有一个项目根目录,该目录下有源代码和测试 但是,我想在我的~/bin目录中编写Python脚本,并在另一个目录中对其进行测试(例如,~/dev/tests)。有没有一种方法可以让我使用命令行界面运行单元测试,而不必设置myPYTHONPATH环境变量并创建\uuuuu init\uuuuuuu.py文件等等 下面是一个简单的示例,演示了我想要的: ~/bin/candy: #!/usr/bin/env python def ca
unittest
模块似乎为项目假设了一个目录结构,其中有一个项目根目录,该目录下有源代码和测试
但是,我想在我的~/bin
目录中编写Python脚本,并在另一个目录中对其进行测试(例如,~/dev/tests
)。有没有一种方法可以让我使用命令行界面运行单元测试,而不必设置myPYTHONPATH
环境变量并创建\uuuuu init\uuuuuuu.py
文件等等
下面是一个简单的示例,演示了我想要的:
~/bin/candy
:
#!/usr/bin/env python
def candy():
return "candy"
if __name__ == '__main__':
print candy()
~/dev/tests/test\u candy.py
:
#!/usr/bin/env python
import unittest
import candy
class CandyTestCase(unittest.TestCase):
def testCandy(self):
candyOutput = candy.candy()
assert candyOutput == "candy"
我注意到,如果:
- 这两个文件以py扩展名命名(
和candy.py
)test\u candy.py
- 这两个文件位于同一目录中
- 测试在测试目录中使用以下内容运行: $python-m单元测试
unittest
模块运行python来执行以下操作,而无需在我的环境中明确设置任何内容:
- 我的测试文件没有py扩展名(只是
)~/candy
- 我不在乎
是否将py作为扩展test\u candy
- 我希望
和candy
不共享公共根目录(我的主目录除外)test\u candy.py
如果简单调用
python-m unittest不可能做到这一点,那么实现这一点最简单的方法是什么?我没有用unittest尝试过这一点,但我的快速修复方法是使用操作系统模块更改脚本中的工作目录。不过这对你应该有用
#!/usr/bin/env python
import unittest
import os
os.chdir("/usr/bin/candy")
import candy
class CandyTestCase(unittest.TestCase):
def testCandy(self):
candyOutput = candy.candy()
assert candyOutput == "candy"
简而言之,不是。问题是你需要导入你要测试的模块,所以至少你必须更改你的PYTHONPATH。我的建议是,在执行测试时暂时更改它,如下所示:
import sys
sys.path.extend(['~/dir1','~/dir2','~/anotherdir'])
@Paritosh_Singh的解决方案很好
从长远来看,需要安装一个测试运行程序,如tox,并对其进行配置,使其“看到”您的模块。但我认为你不想那样做 这是candy可执行文件(无更改):
这是~/dev/tests/test\u candy.py
(已更改):
什么改变了
- 我们添加了
imp.load\u source
以导入~/bin/candy
(一个没有*.py
扩展名的模块)
- 我们增加了使用
expanduser查找主目录的规定,即~
- 我们正在使用
os.path.join
来加入~/bin/candy
现在,您可以使用unittest
模块的discover
选项运行测试
查看python-m unittest--help以了解更多详细信息
以下摘录
-s启动发现的目录('.'默认)
-p匹配测试文件的模式('test*.py'默认值)
自Python 3.3以来,imp
包已被弃用,而importlib
包取代了它。提供如何导入单个文件的详细信息
对于单元测试,这将是:
来自importlib.machine导入模块,SourceFileLoader
从importlib.util从加载程序导入规范,从规范导入模块
导入操作系统路径
导入类型
导入单元测试
def import_from_source(名称:str,文件路径:str)->types.ModuleType:
加载程序:SourceFileLoader=SourceFileLoader(名称、文件路径)
spec:ModuleSpec=spec\u from\u loader(loader.name,loader)
module:types.ModuleType=module\u from\u spec(spec)
loader.exec_模块(模块)
返回模块
脚本路径:str=os.path.abspath(
os.path.join(
os.path.dirname(os.path.abspath(_文件__))、“.”、“.”、“.bin”、“candy”,
)
)
candy:types.ModuleType=import\u from\u source(“candy”,脚本\u路径)
类CandyTestCase(unittest.TestCase):
def testCandy(自:“CandyTestCase”)->无:
self.assertEqual(candy.candy(),“candy”)
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
unittest.main()
假设文件结构为:
base_directory/bin/candy
base_directory/dev/tests/test_candy.py
(注意:此单元测试假定来自测试的固定相对路径,而不是固定绝对路径,以便您可以将包移动到另一个目录,并且只要包中的文件不改变相对位置,测试就不会中断。)为什么编写python文件时没有扩展名.py
呢?python库中的模块应该有.py扩展名。另一方面,可执行脚本,无论是shell、perl、python还是其他什么,都不需要.ksh、.bash、.py等扩展,因为它们的用户不需要知道如何用什么语言实现它们来运行它们。我通常不使用扩展名来命名可执行文件,扩展名表示脚本的类型。对于临时测试来说,这样做很容易,只需使用imp.load\u source(模块名称,'bin/EXECUTABLE\u FILE')
,我发现我遇到的问题是在执行去ILD时,它不会将不以.py结尾的文件复制到build dir,这样这些脚本就不会在build@PeterTurner你能再详细一点吗?您正在执行什么类型的构建?如果是distutils
/setuptools
build,那么通过scripts
列表传递到setup
函数的脚本将复制到build/scripts-X.Y
,其中X.Y是解释器版本。@hoefling,哦,我没有“scripts”列表,我必须查一下,我正在用一些参数做一个去毛刺,一时记不起来了,我周一会查的
➜ cat ~/dev/tests/test_candy.py
#!/usr/bin/env python
import imp
import unittest
from os.path import expanduser, join
# use expanduser to locate its home dir and join bin and candy module paths
candy_module_path = join(expanduser("~"), "bin", "candy")
# load the module without .py extension
candy = imp.load_source("candy", candy_module_path)
class CandyTestCase(unittest.TestCase):
def testCandy(self):
candyOutput = candy.candy()
assert candyOutput == "candy"
➜ python -m unittest discover -s ~/bin/ -p 'test*' -v ~/dev/tests
testCandy (test_candy.CandyTestCase) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
base_directory/bin/candy
base_directory/dev/tests/test_candy.py