flask тестирование не может установить flask .g с помощью appcontext_push.connected_to - PullRequest
0 голосов
/ 05 марта 2020

Мой код неверен .. Итак, вопрос окончен. Большое спасибо.

=================== Происхождение вопроса ⬇️ == ===============

Я пытаюсь проверить мое приложение flask (python3 .8.1), следуя flask -do c

flask -до c

Я хочу установить flask .g для моего приложения перед запросом в тестировании, поэтому я использую appcontext_push.connected_to забавно c, но это не работает ...

Я создаю небольшую демонстрацию здесь. Вы можете попробовать скопировать его в demo.py

pip install flask, binker, pytest

pytest demo.py

You получит AttributeError: у объекта '_AppCtxGlobals' нет атрибута 'name' .......

Почему ...

from contextlib import contextmanager
from flask import appcontext_pushed, g, json, jsonify, Flask


app = Flask(__name__)


def fetch_current_user_from_database():
    return {'name': 'aa'}


def get_user():
    user = getattr(g, 'user', None)
    if user is None:
        user = fetch_current_user_from_database()
        g.name = user['name']
    return user


@app.route('/users/me')
def users_me():
    return jsonify(username=g.name)


@contextmanager
def user_set(app, user):
    def handler(sender, **kwargs):
        g.user = user
    with appcontext_pushed.connected_to(handler, app):
        yield


def test_1():
    username = '123'
    with user_set(app, username):
        with app.test_client() as c:
            resp = c.get('/users/me')
            data = json.loads(resp.data)
            assert data['username'] == username

Ответы [ 2 ]

0 голосов
/ 06 марта 2020

Правильный код:

from contextlib import contextmanager
from flask import appcontext_pushed, g, json, jsonify, Flask


app = Flask(__name__)


@app.route('/users/me')
def users_me():
    return jsonify(username=g.user)


@contextmanager
def user_set(app, user):
    def handler(sender, **kwargs):
        g.user = user
    with appcontext_pushed.connected_to(handler, app):
        yield


def test_1():
    user = '123'
    with user_set(app, user):
        with app.test_client() as c:
            resp = c.get('/users/me')
            data = json.loads(resp.data)
            assert data['username'] == user

Это демо, как я сказал. В моем реальном приложении я хочу отправить пользовательский объект в g, который создан с помощью функции ниже.

def login(client, email, password):
    print(f'login_info test start')
    ret = client.post('/api/login', json=dict(
        email=email,
        password=password
    ), follow_redirects=True)
    assert ret.status_code == 200
    data = json.loads(ret.data)
    uid = data['uid']
    customer = CustomerService.get(uid)
    print(f'login test end {customer.email}')
    assert customer

вы можете заметить, что в функции нет возврата. Так что я получаю None и отправляю это g. Но я не заметил, что это ночью.

flask -do c имеет некоторые неполные и неоднозначные демо:

with user_set(app, my_user):
    with app.test_client() as c:
        resp = c.get('/users/me')
        data = json.loads(resp.data)
        self.assert_equal(data['username'], my_user.username)

, если приложение меняется на flaskr, я могу иметь больше смелости попробовать.

with user_set(flaskr, my_user):
    with app.test_client() as c:
        resp = c.get('/users/me')
        data = json.loads(resp.data)
        self.assert_equal(data['username'], my_user.username)

Я ищу в Google около 5 часов, чтобы выяснить, почему appcontext_push.connected_to ничего не отправлять ... Каждое полученное мной демо не работает. У меня кончилось мужество.

спасибо, что ответил на такой простой вопрос. Вы показываете, что это действительно работает, что-то не так в моем собственном коде. Вы даете мне мужество, которое действительно много значит. Еще раз спасибо!

0 голосов
/ 05 марта 2020

Вы переписали некоторые части примера из документации, и поэтому g.name не существует, когда вызывается users_me(). fetch_current_user_from_database() и get_user() кажутся мне неуместными в вашем примере. Вы не проверяете их, и им никогда не звонят. Похоже, что ваш тест проверяет только то, что users_me() возвращает имя пользователя.

Поэтому в тесте вы должны установить весь пользовательский объект. Что это за объект, зависит от вашего приложения, потому что это не Flask -specifi c. Учитывая, что вы не предоставили такую ​​информацию, давайте просто использовать фиктивный объект:

from unittest.mock import MagicMock

from contextlib import contextmanager
from flask import appcontext_pushed, g, json, jsonify, Flask


app = Flask(__name__)

@app.route('/users/me')
def users_me():
    return jsonify(username=g.user.name)


@contextmanager
def user_set(app, user):
    def handler(sender, **kwargs):
        g.user = user

    with appcontext_pushed.connected_to(handler, app):
        yield

def test_1():
    user = MagicMock()
    user.name = 'aa'

    with user_set(app, user):
        with app.test_client() as c:
            resp = c.get('/users/me')
            data = json.loads(resp.data)
            assert data['username'] == user.name
...