Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/362.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在pytest中每次测试后完全拆卸烧瓶应用程序?_Python_Flask_Pytest - Fatal编程技术网

Python 如何在pytest中每次测试后完全拆卸烧瓶应用程序?

Python 如何在pytest中每次测试后完全拆卸烧瓶应用程序?,python,flask,pytest,Python,Flask,Pytest,我正在使用Pytest测试我的Flask应用程序。我有3个文件 tests/ --conftest.py --test_one.py --test_two.py 如果我使用以下命令运行test\u one.py或test\u two.py,它将正常工作 python -m pytest tests/test_one.py 当我尝试使用以下命令运行所有测试时,会出现问题: python -m pytest tests 我得到这个错误: AssertionError: View functio

我正在使用Pytest测试我的Flask应用程序。我有3个文件

tests/
--conftest.py
--test_one.py
--test_two.py
如果我使用以下命令运行
test\u one.py
test\u two.py
,它将正常工作

python -m pytest tests/test_one.py
当我尝试使用以下命令运行所有测试时,会出现问题:

python -m pytest tests
我得到这个错误:

AssertionError: View function mapping is overwriting an existing endpoint function: serve_static
实际上,我对这个错误并不感到惊讶,因为
init\u app(app)
会被调用两次(每个文件一次),而且我从来没有拆卸过实际的
app


我的问题是,有没有一种方法可以完全拆卸一个flask应用程序并为每个单独的测试重新构建它?我正在寻找执行拆卸的实际命令(即
app.teardown()

编辑:如果Flask应用程序测试环境能够解决此问题(无需创建新环境),我愿意选择其他方法来设置Flask应用程序测试环境

编辑2:我发现了一个问题。这是类似的,可以解决我的问题,但它涉及到在函数内部导入。我想一定有更好的办法

conftest.py

import os
import pytest

from app import app, init_app
from config import TestConfig


@pytest.fixture(scope='function')
def client():

    app.config.from_object(TestConfig)

    with app.test_client() as client:
        with app.app_context():
            init_app(app)
        yield client

    try:
        os.remove('tests/testing.db')
    except FileNotFoundError:
        pass
app = Flask(__name__)
app.url_map._rules.clear()
db = SQLAlchemy(app)
migrate = Migrate(app, db)

def init_app(app):
    ...
def create_app(config)
    app = Flask(__name__)
    app.url_map._rules.clear()
    from .models import db
    app.config.from_object(config)
    with app.app_context():

    return app

def init_app(app):
    ...
import os
import pytest

from app import create_app, init_app
from config import TestConfig


@pytest.fixture(scope='function')
def client():
    app = create_app()
    app.config.from_object(TestConfig)

    with app.test_client() as client:
        with app.app_context():
            from app.models import db
            init_app(app, db)
            yield client

    try:
        os.remove('tests/testing.db')
    except FileNotFoundError:
        pass
app/\uuuu init\uuuuu.py

import os
import pytest

from app import app, init_app
from config import TestConfig


@pytest.fixture(scope='function')
def client():

    app.config.from_object(TestConfig)

    with app.test_client() as client:
        with app.app_context():
            init_app(app)
        yield client

    try:
        os.remove('tests/testing.db')
    except FileNotFoundError:
        pass
app = Flask(__name__)
app.url_map._rules.clear()
db = SQLAlchemy(app)
migrate = Migrate(app, db)

def init_app(app):
    ...
def create_app(config)
    app = Flask(__name__)
    app.url_map._rules.clear()
    from .models import db
    app.config.from_object(config)
    with app.app_context():

    return app

def init_app(app):
    ...
import os
import pytest

from app import create_app, init_app
from config import TestConfig


@pytest.fixture(scope='function')
def client():
    app = create_app()
    app.config.from_object(TestConfig)

    with app.test_client() as client:
        with app.app_context():
            from app.models import db
            init_app(app, db)
            yield client

    try:
        os.remove('tests/testing.db')
    except FileNotFoundError:
        pass

我将在您的每个文件中创建一个继承TestCase的类。通过这种方式,您可以在每次测试之前使用函数
setup()
生成testclient作为实例变量。通过这种方式,您可以确保每个测试都有相同的工作环境

from unittest import TestCase
from app import app as application

class TestApplication(TestCase):
  def setUp(self):
    self.client = application.app.test_client()

  def test_sth(self):
    r = self.client.get('/approute2sth')
    self.assertEqual(r.status_code, 200)

  def test_sth_else(self):
    r = self.client.get('/approute2sth_else')
    self.assertEqual(r.status_code, 200)

我正在考虑一个解决方案,但不涉及拆除烧瓶应用程序。我不喜欢对每个测试用例都拆下它,因为这本身会增加每个测试用例的正常运行时间(除非flask应用程序初始化对每个测试用例都是唯一的)

由于测试在pytest中并行运行,因此可以执行以下操作

try:
    app
except NameError:
    app.config.from_object(TestConfig)
    with app.test_client() as client:
        with app.app_context():
            init_app(app)
else:
    print("App is already configured. Let us proceed with the test case")

您可以将其包装为一个单例类,而不是采用上述方法

以下方法的某些组合可能会起作用。我相信这是老办法(尽管我自己从来没有做过)。我的印象是,
pytest
使用fixture的概念使直接
teardown()变得不必要

#clear current db session
db.session.remove()
#drop all tables in db
db.drop_all()
#remove app_context
app.app_context.pop()

有关更多讨论,请参阅

最终我的问题是如何创建我的
应用程序。由于它是在
\uuu init\uuuuuuy.py
中作为gloval变量创建的,因此我无法为每个测试重新创建它。我重构了
\uuuu init\uuuuuuuy.py
(以及我的其余代码)以使用
创建应用程序
函数,在该函数中我可以反复创建相同的应用程序。下面的代码最终成功了

app/\uuuu init\uuuuu.py

import os
import pytest

from app import app, init_app
from config import TestConfig


@pytest.fixture(scope='function')
def client():

    app.config.from_object(TestConfig)

    with app.test_client() as client:
        with app.app_context():
            init_app(app)
        yield client

    try:
        os.remove('tests/testing.db')
    except FileNotFoundError:
        pass
app = Flask(__name__)
app.url_map._rules.clear()
db = SQLAlchemy(app)
migrate = Migrate(app, db)

def init_app(app):
    ...
def create_app(config)
    app = Flask(__name__)
    app.url_map._rules.clear()
    from .models import db
    app.config.from_object(config)
    with app.app_context():

    return app

def init_app(app):
    ...
import os
import pytest

from app import create_app, init_app
from config import TestConfig


@pytest.fixture(scope='function')
def client():
    app = create_app()
    app.config.from_object(TestConfig)

    with app.test_client() as client:
        with app.app_context():
            from app.models import db
            init_app(app, db)
            yield client

    try:
        os.remove('tests/testing.db')
    except FileNotFoundError:
        pass
conftest.py

import os
import pytest

from app import app, init_app
from config import TestConfig


@pytest.fixture(scope='function')
def client():

    app.config.from_object(TestConfig)

    with app.test_client() as client:
        with app.app_context():
            init_app(app)
        yield client

    try:
        os.remove('tests/testing.db')
    except FileNotFoundError:
        pass
app = Flask(__name__)
app.url_map._rules.clear()
db = SQLAlchemy(app)
migrate = Migrate(app, db)

def init_app(app):
    ...
def create_app(config)
    app = Flask(__name__)
    app.url_map._rules.clear()
    from .models import db
    app.config.from_object(config)
    with app.app_context():

    return app

def init_app(app):
    ...
import os
import pytest

from app import create_app, init_app
from config import TestConfig


@pytest.fixture(scope='function')
def client():
    app = create_app()
    app.config.from_object(TestConfig)

    with app.test_client() as client:
        with app.app_context():
            from app.models import db
            init_app(app, db)
            yield client

    try:
        os.remove('tests/testing.db')
    except FileNotFoundError:
        pass

我正在寻找将flask应用程序拆掉的实际代码,这样我就可以重新导入或重新初始化,而无需获得
AssertionError
。我认为如果您可以将创建
app
的代码包含在
app
的位置,这会很有帮助。@LuisOrduz-我在
应用程序的位置添加了
app/\uuuuu init\uuuuuuuuuuuuupy
的相关部分创建。任何阅读以下内容的人:使用pluginIf测试状态在单元测试之间进行,幂等性将丢失,并且可能发生令人惊讶的行为。因此,一方面,书写的速度和便捷性,另一方面,书写的安全性之间存在着一种折衷。很明显,它依赖于用例。