跨应用程序/测试的python导入更优雅的解决方案?
我试图通过将测试放在我的应用程序的一个单独目录中来合理地组织我的代码。但是,导入可以用于应用程序或测试,但不能同时用于两者。下面是一个人为的例子,说明了我当前的问题:跨应用程序/测试的python导入更优雅的解决方案?,python,unit-testing,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.EXAM
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())
EXAMPLE = "Wow$ Python$"
DELIM = "$"
import settings
class Moods:
def __init__(self, text):
self.text = text
def excited(self):
return self.text.replace(settings.DELIM, "!!!")
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()
设置.py
import settings
from moods import Moods
words = Moods(settings.EXAMPLE)
print(words.excited())
EXAMPLE = "Wow$ Python$"
DELIM = "$"
import settings
class Moods:
def __init__(self, text):
self.text = text
def excited(self):
return self.text.replace(settings.DELIM, "!!!")
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()
moods.py
import settings
from moods import Moods
words = Moods(settings.EXAMPLE)
print(words.excited())
EXAMPLE = "Wow$ Python$"
DELIM = "$"
import settings
class Moods:
def __init__(self, text):
self.text = text
def excited(self):
return self.text.replace(settings.DELIM, "!!!")
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()
测试情绪.py
import settings
from moods import Moods
words = Moods(settings.EXAMPLE)
print(words.excited())
EXAMPLE = "Wow$ Python$"
DELIM = "$"
import settings
class Moods:
def __init__(self, text):
self.text = text
def excited(self):
return self.text.replace(settings.DELIM, "!!!")
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行修改为从应用程序导入设置中读取,测试将通过,但应用程序的正常执行将失败,因为它没有看到模块app
我能想到的唯一解决办法是
将测试放在与代码相同的目录中(我试图避免这样做)
将sys.path.insert(0,os.path.abspath('..'))
添加到我的应用程序中的每个文件,以使导入的工作方式与测试导入的工作方式相同(这看起来很混乱)
有没有更优雅的方法来解决这个导入问题?您应该在PYTHONPATH
中同时拥有app
和test
目录
一种方法是替换此选项:
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
environment变量
为什么??因为当您运行main.py
时,app
在路径中,而不是app/.
,所以您希望在运行测试时拥有相同的路径。您应该在PYTHONPATH
中同时拥有app
和test
目录
一种方法是替换此选项:
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
environment变量
为什么??因为当您运行main.py
时,app
在路径中,而不是app/。
,所以您希望在运行测试时具有相同的路径。Hmm。。。到目前为止,这一解决方案似乎是最有希望的。它是干净的,并保持对测试文件的路径修改。但是,它不起作用。实现上面建议的代码更改会产生:importorror:没有名为“moods”的模块。
Ok。。。奇怪的是,设置os.path.abspath('app')
起了作用。我想这是因为我从父目录运行测试,并且它知道应用程序目录?@vastlysuperiorman如果你从父目录运行,那么app
是正确的路径,是的。嗯。。。到目前为止,这一解决方案似乎是最有希望的。它是干净的,并保持对测试文件的路径修改。但是,它不起作用。实现上面建议的代码更改会产生:importorror:没有名为“moods”的模块。
Ok。。。奇怪的是,设置os.path.abspath('app')
起了作用。我想这是因为我正在从父目录运行测试,并且它知道app目录?@vastlysuperiorman如果您正在从父目录运行,那么app
是正确的路径,是的。