在我的包的子包中运行python脚本

时间:2014-06-04 22:31:05

标签: python import packages

在找出正确的,python 2.x首选方式进行相对导入时遇到一些麻烦,这样我就可以将测试脚本保存在一个子包中,让这些测试脚本能够测试我的库。

$ farm\testpad\testpad.py
Traceback (most recent call last):
  File "C:\farm\testpad\testpad.py", line 4, in <module>
    from ..animals.dog import dog
ValueError: Attempted relative import in non-package

$ python -m farm\testpad\testpad
C:\Python27\python.exe: No module named farm\testpad\testpad

在以下示例中,我需要修改哪些内容才能执行我想要的操作?拜托,感谢您给予的任何帮助。

e.g。

包结构:

farm/
    __init__.py # empty
    animals/
        __init__.py # empty
        dog.py
    testpad/
        __init__.py # empty
        testpad.py

dog.py

import sys
import os

class dog():
  def __init__(self, name):
    self.name = name

  def speak(self):
    print "woof"

testpad.py

import os
import sys

from ..animals.dog import dog

# create a dog and test its speak action
def testpad():
  d = dog("Allen")
  d.speak()

if __name__ == "__main__":
  testpad()

1 个答案:

答案 0 :(得分:17)

三件事:

  • 始终从项目的根目录运行测试脚本。这个简单的规则不会对任何事情造成伤害,并且会简化您的方案
  • 更喜欢绝对进口
  • -m python选项需要虚线形式的模块

将此应用于您的代码

修改testpad.py

import os
import sys

from farm.animals.dog import dog

# Create a dog and test its speak action

    def testpad():
      d = dog("Allen")
      d.speak()

    if __name__ == "__main__":
      testpad()

python -m <module>

调用它
$ python -m farm.testpad.testpad
woof

奖金 - 从nose

进行测试

对于我的测试,我使用以下模式

  • 将所有测试代码保存在名为test或更好tests
  • 的项目子目录中
  • 使用nose测试框架

在项目的根目录

安装nose

$ pip install nose

创建命令的内容nosetests

重新组织您的代码

$ mkdir tests
$ mv farm/testpad/testpad.py tests/test_animals.py
$ rm -rf farm/testpad/

运行测试(目前只有一个)

简单的方法,这项工作,但试图保持输出最小:

$ nosetests
.
----------------------------------------------------------------------
Ran 1 test in 0.003s

OK

如您所见,鼻子正在自己发现测试用例(搜索以test开头的任何内容)

让它更冗长:

$ nosetests -v
test_animals.testpad ... ok

----------------------------------------------------------------------
Ran 1 test in 0.003s

OK

现在你知道了,运行了什么测试。

要查看捕获的输出,请使用-s开关:

$ nosetests -vs
test_animals.testpad ... woof
ok

----------------------------------------------------------------------
Ran 1 test in 0.003s

OK

test_animals.py

添加更多测试
import os
import sys

# create a dog and test its speak action
def test_dog():
    from farm.animals.dog import dog
    d = dog("Allen")
    d.speak()

def test_cat():
    from farm.animals.dog import cat
    c = cat("Micy")
    d.speak()

def test_rabbit():
    from farm.animals.dog import rabbit
    r = rabbit()
    r.speak()

测试它:

$ nosetests -vs
test_animals.test_dog ... woof
ok
test_animals.test_cat ... ERROR
test_animals.test_rabbit ... ERROR

======================================================================
ERROR: test_animals.test_cat
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/javl/Envs/so/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/home/javl/sandbox/so/testpad/tests/test_animals.py", line 12, in test_cat
    from farm.animals.dog import cat
ImportError: cannot import name cat

======================================================================
ERROR: test_animals.test_rabbit
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/javl/Envs/so/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/home/javl/sandbox/so/testpad/tests/test_animals.py", line 17, in test_rabbit
    from farm.animals.dog import rabbit
ImportError: cannot import name rabbit

----------------------------------------------------------------------
Ran 3 tests in 0.004s

FAILED (errors=2)

添加--pdb开关以跳转到调试器(如果您安装ipdbplugin,则可以使用--ipdb):

$ nosetests -vs --pdb
test_animals.test_dog ... woof
ok
test_animals.test_cat ... > /home/javl/sandbox/so/testpad/tests/test_animals.py(12)test_cat()
-> from farm.animals.dog import cat
(Pdb) l
  7         from farm.animals.dog import dog
  8         d = dog("Allen")
  9         d.speak()
 10  
 11     def test_cat():
 12  ->     from farm.animals.dog import cat
 13         c = cat("Micy")
 14         d.speak()
 15  
 16     def test_rabbit():
 17         from farm.animals.dog import rabbit
(Pdb) 

使用h或者找一些调试器教程,这是一个很棒的工具

真实的测试用例应断言行为符合预期。

断言打印值如预期

当您打印到stdout时,我们可以使用模拟捕获输出(在Python 2.x中您必须安装它,在Python 3.x中from unittest import mock):

$ pip install mock

并修改您的test_animals.py

from mock import patch
from StringIO import StringIO

# create a dog and test its speak action
@patch("sys.stdout", new_callable=StringIO)
def test_dog(mock_stdout):
    from farm.animals.dog import Dog
    d = Dog("Allen")
    d.speak()
    assert mock_stdout.getvalue() == "woof\n"

@patch("sys.stdout", new_callable=StringIO)
def test_cat(mock_stdout):
    from farm.animals.cat import Cat
    c = Cat("Micy")
    c.speak()
    assert mock_stdout.getvalue() == "mnau\n"

@patch("sys.stdout", new_callable=StringIO)
def test_rabbit(mock_stdout):
    from farm.animals.rabbit import Rabbit
    r = Rabbit("BB")
    r.speak()
    assert mock_stdout.getvalue() == "Playboy, Playboy\n"

我品尝的最终测试用例test_mytaste.py

def test_dog():
    from farm.animals.dog import Dog
    d = Dog("Allen")
    sound = d.speak()
    assert sound == "woof", "A dog shall say `woof`"

def test_cat():
    from farm.animals.cat import Cat
    c = Cat("Micy")
    sound = c.speak()
    assert sound == "mnau", "A cat shall say `mnau`"

def test_rabbit():
    from farm.animals.rabbit import Rabbit
    r = Rabbit("BB")
    sound = r.speak()
    assert sound == "Playboy, Playboy", "A Rabbit shall say ..."

这需要你重构你的代码(类名从大写开始,speak方法不打印但返回声音。)

事实上,您可能会从测试用例开始编写代码并稍后添加经过测试的模块,这通常会导致更好的设计,因为您从一开始就考虑实际使用。

选择性调用测试用例

nose非常适合搜索测试用例(通常以test开头),但有时您可能会专注于特定测试或使用不同名称的python文件。您可以告诉nose只使用一个测试文件:

$ nosetests -vs tests/test_mytaste.py 
test_mytaste.test_dog ... ok
test_mytaste.test_cat ... ok
test_mytaste.test_rabbit ... ok

----------------------------------------------------------------------
Ran 3 tests in 0.002s

OK

或甚至定位nose从中运行特定测试:

$ nosetests -vs tests/test_mytaste.py:test_dog
test_mytaste.test_dog ... ok

----------------------------------------------------------------------
Ran 1 test in 0.001s

OK