使用py.test进行单元测试时,"RuntimeError:在应用程序上下文之外工作"

 sannyi 发布于 2023-01-01 18:50

我正在尝试迁移到py.test以便于使用和自动发现测试.当我使用unittest运行测试时,测试工作正常.当我在py.test下运行测试时,我得到了RuntimeError: working outside of application context.

这是测试代码(test_app.py):

import unittest

from app import app

class TestAPILocally(unittest.TestCase):
    def setUp(self):
        self.client = app.test_client()

    def testRoot(self):
        retval = self.client.get('/').data
        self.assertTrue('v1' in retval)

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

这是我正在测试的精简文件(app.py):

from flask import Flask
from flask.ext.restful import Api, Resource

class APIListAPI(Resource):
    def get(self):
        return ['v1']

app = Flask(__name__)
api = Api(app)
api.add_resource(APIListAPI, '/')

正如您所看到的,这与烧瓶站点上的文档非常相似:测试骨架,实际上,当我使用unittest运行它时,它成功:

$ python tmp1/test_app.py 
.
----------------------------------------------------------------------
Ran 1 test in 0.115s

OK
$ 

但是,当我用py.test测试时,它失败了:

$ ./py.test tmp1/test_app.py
=================== test session starts =========================
platform sunos5 -- Python 2.7.5 -- py-1.4.22 -- pytest-2.6.0
collected 1 items

tmp1/test_app.py F

========================= FAILURES ==============================
_________________ TestAPILocally.testRoot _______________________

self = 

    def testRoot(self):
>       retval = self.client.get('/').data

tmp1/test_app.py:10:
 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
werkzeug/test.py:762: in get
    return self.open(*args, **kw)
flask/testing.py:108: in open
    follow_redirects=follow_redirects)
werkzeug/test.py:736: in open
    response = self.run_wsgi_app(environ, buffered=buffered)
werkzeug/test.py:659: in run_wsgi_app
    rv = run_wsgi_app(self.application, environ, buffered=buffered)
werkzeug/test.py:855: in run_wsgi_app
    app_iter = app(environ, start_response)
tmp1/flask/app.py:1836: in __call__
    return self.wsgi_app(environ, start_response)
tmp1/flask/app.py:1820: in wsgi_app
    response = self.make_response(self.handle_exception(e))
flask_restful/__init__.py:256: in error_router
    if self._has_fr_route():
flask_restful/__init__.py:237: in _has_fr_route
    if self._should_use_fr_error_handler():
flask_restful/__init__.py:218: in _should_use_fr_error_handler
    adapter = current_app.create_url_adapter(request)
werkzeug/local.py:338: in __getattr__ 
    return getattr(self._get_current_object(), name)
werkzeug/local.py:297: in _get_current_object
    return self.__local()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    def _find_app():
        top = _app_ctx_stack.top
        if top is None:
>           raise RuntimeError('working outside of application context')
E           RuntimeError: working outside of application context

flask/globals.py:34: RuntimeError
================ 1 failed in 1.02 seconds ======================

现在,事实证明,我可以通过这样做来使这个测试通过:

$ rm tmp1/__init__.py

并通过这样做使它再次失败:

$ touch tmp1/__init__.py

那么,unittest和py.test处理模块中文件的方式有什么区别吗?看起来非常奇怪,它足以让Flask抱怨,因为我显然在调用app.test_client().get()的应用程序上下文中.这是预期的行为,还是应该针对py.test提出错误?

如果它是相关的,我从父目录执行测试的原因是因为我没有能力将模块添加到site-packages,所以我从父目录启动我的所有代码,我在那里我安装了Flask,py.test等.

编辑:解决了.这是一个安装问题.添加pythonpath标记,因为那是解决方案.

2 个回答
  • 您可以手动设置应用上下文:

    app = Flask(__name__)
    ctx = app.app_context()
    ctx.push()
    
    with ctx:
        pass
    

    2023-01-01 18:52 回答
  • 不直接回答TS问题,但主要是针对"应用程序上下文"错误.

    在setUp和tearDown函数中添加推送和弹出上下文应该有助于解决此错误:

    def setUp(self):
        self.app_context = app.app_context()
        self.app_context.push()
    
    def tearDown(self):
        self.app_context.pop()
    

    您可以在那里找到有关烧瓶背景的更多信息:

    http://flask.pocoo.org/docs/appcontext/

    http://flask.pocoo.org/docs/reqcontext/

    丹尼尔克罗诺维特在这篇很棒的文章中也写道:

    http://kronosapiens.github.io/blog/2014/08/14/understanding-contexts-in-flask.html

    PS如果您计划在测试中使用url_for,则需要进行其他配置:

    @classmethod
    def setUpClass(cls)
        app.config['SERVER_NAME'] = 'localhost:5000'
    

    class ViewsTestCase(unittest.TestCase):
        @classmethod
        def setUpClass(cls):
            app.config['SERVER_NAME'] = 'localhost:5000'
            cls.client = app.test_client()
    
        def setUp(self):
            self.app_context = app.app_context()
            self.app_context.push()
    
        def tearDown(self):
            self.app_context.pop()
    
        def test_view_should_respond(self):
            r = self.client.get(url_for("index"))
            self.assertEqual(r.status_code, 200)
    

    2023-01-01 18:52 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有