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

mco*_*ley 10 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
Run Code Online (Sandbox Code Playgroud)

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

例如

包装结构:

farm/
    __init__.py # empty
    animals/
        __init__.py # empty
        dog.py
    testpad/
        __init__.py # empty
        testpad.py
Run Code Online (Sandbox Code Playgroud)

dog.py

import sys
import os

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

  def speak(self):
    print "woof"
Run Code Online (Sandbox Code Playgroud)

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()
Run Code Online (Sandbox Code Playgroud)

Jan*_*sky 21

三件事:

  • 始终从项目的根目录运行测试脚本.这个简单的规则不会伤害任何东西,并会简化您的方案
  • 更喜欢绝对进口
  • -mpython期望模块的选项以虚线形式

将此应用于您的代码

修改 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()
Run Code Online (Sandbox Code Playgroud)

从中调用它 python -m <module>

$ python -m farm.testpad.testpad
woof
Run Code Online (Sandbox Code Playgroud)

奖金 - 来自的测试 nose

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

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

成为你项目的根源

安装nose:

$ pip install nose
Run Code Online (Sandbox Code Playgroud)

什么创造了一个命令 nosetests

重新组织您的代码

$ mkdir tests
$ mv farm/testpad/testpad.py tests/test_animals.py
$ rm -rf farm/testpad/
Run Code Online (Sandbox Code Playgroud)

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

这种简单的方式,但是会尝试保持输出最小化:

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

OK
Run Code Online (Sandbox Code Playgroud)

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

让它更冗长:

$ nosetests -v
test_animals.testpad ... ok

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

OK
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

OK
Run Code Online (Sandbox Code Playgroud)

添加更多测试 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()
Run Code Online (Sandbox Code Playgroud)

测试一下:

$ 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)
Run Code Online (Sandbox Code Playgroud)

添加--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) 
Run Code Online (Sandbox Code Playgroud)

使用h或找到一些调试器教程,它是很棒的工具

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

断言打印值与预期一致

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

$ pip install mock
Run Code Online (Sandbox Code Playgroud)

并修改你的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"
Run Code Online (Sandbox Code Playgroud)

我最后的测试案例 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 ..."
Run Code Online (Sandbox Code Playgroud)

这需要您重构代码(类名从大写开始,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
Run Code Online (Sandbox Code Playgroud)

甚至是nose从中运行特定测试的目标:

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

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

OK
Run Code Online (Sandbox Code Playgroud)

  • @ shx2我的"首选绝对导入"遵循[PEP 8](http://legacy.python.org/dev/peps/pep-0008/#id17),建议使用绝对导入.你有更好的Python代码通用规则来源吗? (2认同)