跨app / tests的python导入更优雅的解决方案?

时间:2016-10-24 16:46:00

标签: python unit-testing

我正在尝试通过将测试放在与我的应用程序不同的目录中来合理地组织我的代码。但是,导入为应用程序执行 ,但不能同时执行这两项操作。这是一个人为的例子,说明了我目前的问题:

myapp/
  app/
    main.py
    settings.py
    moods.py
  test/
    test_moods.py

文件内容如下:

main.py

import settings
from moods import Moods

words = Moods(settings.EXAMPLE)
print(words.excited())

settings.py

EXAMPLE = "Wow$ Python$"
DELIM = "$"

moods.py

import settings

class Moods:
    def __init__(self, text):
        self.text = text

    def excited(self):
        return self.text.replace(settings.DELIM, "!!!")

test_moods.py

import sys, os, unittest
sys.path.insert(0, os.path.abspath('..'))

from app.moods import Moods

class TestMood(unittest.TestCase):
    def setUp(self):
        self.words = Moods("Broken imports$ So sad$")

    def test_mood(self):
        self.assertEqual(self.words.excited(), "Broken imports!!! So sad!!!")
        with self.assertRaises(AttributeError):
            self.words.angry()

if __name__ == "__main__":
    unittest.main()

在当前状态下,从myapp/我可以成功运行以下命令:

>> python3 app/main.py
Wow!!! Python!!!

但是当我尝试运行测试时,在moods.py中导入失败:

>> python3 -m unittest discover test/
ImportError: Failed to import test module: test_moods
[ stack trace here pointing to first line of moods.py ]
ImportError: No module named 'settings'

如果我将moods.py的第1行修改为from app import settings,则测试将通过,但应用程序的正常执行会失败,因为它看不到模块app

我能想到的唯一解决方案是

  1. 将测试放在与代码相同的目录中(我试图避免)
  2. sys.path.insert(0, os.path.abspath('..'))添加到我的应用中的每个文件,以使导入的工作与测试的相同(这看起来很混乱)
  3. 是否有更优雅的方法来解决这个导入问题?

1 个答案:

答案 0 :(得分:2)

您应该在app中同时拥有testPYTHONPATH目录。

一种方法是替换它:

sys.path.insert(0, os.path.abspath('..'))

from app.moods import Moods

用这个:

sys.path.insert(0, os.path.abspath('../app'))

from moods import Moods

或者您可以在运行测试之前设置PYTHONPATH environament变量。

为什么呢?因为当您运行main.py时,app位于路径中,而不是app/..,因此您希望在运行测试时保持相同。