我正在努力了解如何在Flask中编写测试。
我继承了一个应用程序,该应用程序已经进行了许多测试,这些测试可以测试诸如/login
之类的路由,并测试响应是否符合预期。
我的情况要复杂得多。我需要测试一种路由/方法,该方法取决于情况,点击外部api,弄清应用程序本身正在运行的容器中是否存在路径,启动一个过程需要花费10分钟以上的时间才能在另一台计算机上运行- -各种各样的事情。因此,我不能只是沿着路线去看看我是否得到了想要的东西。我需要模拟和打补丁以模仿各种外部世界状态的影响。
现在我在brain_db/views.py
中定义了一条路由:
@app.route('/label_view/<int:scan_number>')
@login_required
def label_view(scan_number):
<so much complicated logic>
在同一文件brain_db/views.py
中定义的第一个路由是
@app.route('/surface_test')
def surface_test():
<some code>
这是抛出错误的文件的简化版本:
import unittest
from mock import MagicMock, patch
from flask_brain_db.test_helpers import set_up, tear_down
from flask_brain_db.brain_db.models import Scan
from brain_db.views import label_view
class BrainDBTest(unittest.TestCase):
def setUp(self):
app, db = set_up()
scan = Scan(1, '000001', '000001_MR1', 'scan.nii.gz', scan_number=1)
db.session.add(scan)
scan = Scan.query.filter(Scan.scan_number == 1).first()
db.session.commit()
def tearDown(self):
tear_down()
def mock_volume_views_setup(self)
scan = Scan.query.filter(Scan.scan_number == 1).first()
container_file_path = '/path/to/file/in/container'
return scan, container_file_path
def mock_os_path_exists(self, arg):
return True
@patch('brain_db_helpers.volume_views_setup', mock_volume_views_setup)
@patch('os.path.exists', mock_os_path_exists)
def test_label_view(self):
rv = label_view(1)
assert(True) # I'll actually write tests when I figure out that I can!
print rv
这是错误:
======================================================================
ERROR: brain_db.tests.test (unittest.loader.ModuleImportFailure)
----------------------------------------------------------------------
ImportError: Failed to import test module: brain_db.tests.test
Traceback (most recent call last):
File "/usr/local/lib/python2.7/unittest/loader.py", line 254, in _find_tests
module = self._get_module_from_name(name)
File "/usr/local/lib/python2.7/unittest/loader.py", line 232, in _get_module_from_name
__import__(name)
File "/usr/src/app/flask_brain_db/brain_db/tests/test.py", line 7, in <module>
from brain_db.views import label_view
File "/usr/src/app/flask_brain_db/brain_db/views.py", line 36, in <module>
@app.route('/surface_test')
File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1250, in decorator
self.add_url_rule(rule, endpoint, f, **options)
File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 66, in wrapper_func
return f(self, *args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1221, in add_url_rule
'existing endpoint function: %s' % endpoint)
AssertionError: View function mapping is overwriting an existing endpoint function: surface_test
我为解决问题所做的工作:我读了SO上的许多帖子,它们引用了相同的AssertionError。例如。 1,2。我可以看到问题的总体形状是我的路线已经定义,并且
from brain_db.views import label_view
再次执行views
模块,从而重新定义了路由,因此引发了错误。
我不明白的是我应该如何避免这种情况。我需要能够将方法导入另一个文件才能进行测试。是否所有路径都应包裹在if __name__ == main
中?我是Flask开发的新手,还没有看到这种情况下的示例代码。我怀疑这是正确的解决方案;当您尝试搜索以防止代码在导入时执行时,它只是提供的唯一内容。
我现在运行测试的方式是通过应用程序顶层的文件manage.py
。它包含以下方法:
@manager.command
def test():
"""Runs the tests without coverage"""
tests = unittest.TestLoader().discover(start_dir='.', pattern='test*.py')
res = unittest.TextTestRunner(verbosity=2).run(tests)
sys.exit(not res.wasSuccessful())
我在命令行上运行python manage.py test
。
当我将失败的测试放在brain_db的子模块中时,可能还很重要,但是在它运行之前,先运行了一些测试,这些测试击中了应用程序中定义的路由并测试了预期结果。但是,注释掉这些测试不会影响我的测试失败。
最后,我最初在from flask_brain_db.brain_db.models import Scan
行出现错误:
ERROR: brain_db.tests.test (unittest.loader.ModuleImportFailure)
----------------------------------------------------------------------
ImportError: Failed to import test module: brain_db.tests.test
Traceback (most recent call last):
File "/usr/local/lib/python2.7/unittest/loader.py", line 254, in _find_tests
module = self._get_module_from_name(name)
File "/usr/local/lib/python2.7/unittest/loader.py", line 232, in _get_module_from_name
__import__(name)
File "/usr/src/app/flask_brain_db/brain_db/tests/test.py", line 5, in <module>
from flask_brain_db.brain_db.models import Scan
File "/usr/src/app/flask_brain_db/brain_db/models.py", line 6, in <module>
class Scan(db.Model):
File "/usr/local/lib/python2.7/site-packages/flask_sqlalchemy/model.py", line 67, in __init__
super(NameMetaMixin, cls).__init__(name, bases, d)
File "/usr/local/lib/python2.7/site-packages/flask_sqlalchemy/model.py", line 121, in __init__
super(BindMetaMixin, cls).__init__(name, bases, d)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/ext/declarative/api.py", line 65, in __init__
_as_declarative(cls, classname, cls.__dict__)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 116, in _as_declarative
_MapperConfig.setup_mapping(cls, classname, dict_)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 144, in setup_mapping
cfg_cls(cls_, classname, dict_)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 172, in __init__
self._setup_table()
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 465, in _setup_table
**table_kw)
File "/usr/local/lib/python2.7/site-packages/flask_sqlalchemy/model.py", line 90, in __table_cls__
return sa.Table(*args, **kwargs)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy/sql/schema.py", line 439, in __new__
"existing Table object." % key)
InvalidRequestError: Table 'scan' is already defined for this MetaData instance. Specify 'extend_existing=True' to redefine options and columns on an existing Table object.
我通过添加
使它消失了__table_args__ = {'extend_existing': True}
在模型定义中,但是我不知道是否应该这样做,我怀疑我只是推迟了现在遇到的同样问题。似乎根本的问题是,我不知道如何在不重新定义一堆已经定义的东西的情况下编写测试。
解决此问题的正确方法是什么?如果需要提供其他信息,请告诉我。
答案 0 :(得分:0)
您应该能够从您的应用程序对象访问所有视图功能。尝试从“ brain_db.views import label_view导入”行中删除该行,而在使用以下命令运行set_up()之后定义您的label_view方法:
label_view = app.view_functions [“ label_view”]