Pytest烧瓶请求引荐来源

时间:2018-06-22 15:49:50

标签: python testing flask integration-testing pytest

我目前正在使用Pytest测试我的Flask应用程序,并遇到POST请求和重定向的问题。让我解释一下。

用户想要注册我们的新站点,但必须确认他们拥有其他站点的帐户。一旦他们确认了另一个帐户的凭证,便将其带到注册页面。如果他们来自确认页面,他们只能只能点击注册页面,否则他们将被重定向回首页。

我想测试此功能,并且可以成功向确认页面发出POST请求。如果我未指定follow_redirects=True并打印响应数据,则会得到以下HTML:



  Redirecting...

  

Redirecting...

You should be redirected automatically to target URL: /register?emp_id=1. If not click the link.

太好了!正是我想要的!我想重定向到注册页面。

现在,当我确实指定follow_redirects=True并打印出响应数据时,我希望返回注册页面HTML。相反,响应数据返回主页HTML。

我进一步调查了问题所在。正如我之前提到的,方式可用于进入注册页面,即来自确认页面。在测试期间,我查看了视图中的request.referrer属性,它将返回None。我尝试在测试的POST请求中设置Referrer标头内容,但没有成功。

这是我正在使用的代码:

views.py

@app.route('/confirm', methods=['GET', 'POST'])
def confirm_bpm():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = BPMLoginForm()
    if form.validate_on_submit():
        bpm_user = BPMUser.query\
            .filter(and_(BPMUser.group_name == form.group_name.data,
                         BPMUser.user_name == form.username.data,
                         BPMUser.password == encrypt(form.password.data)))\
            .first()
        if not bpm_user:
            flash('BPM user account does not exist!')
            url = url_for('confirm_bpm')
            return redirect(url)
        if bpm_user.user_level != 3:
            flash('Only L3 Users can register through this portal.')
            url = url_for('confirm_bpm')
            return redirect(url)
        url = url_for('register', emp_id=bpm_user.emp_id)
        return redirect(url)
    return render_template('login/confirm_bpm.html', form=form)

@app.route('/register', methods=['GET', 'POST'])
def register():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    if request.method == 'GET' and\
            request.referrer != request.url_root + 'confirm':
        return redirect(url_for('index'))

    emp_id = request.args.get('emp_id')
    emp_id_exists = User.query.filter_by(emp_id=emp_id).first()
    if emp_id_exists:
        flash('User is already registered!')
        return redirect(url_for('login'))

    form = RegistrationForm()
    if form.validate_on_submit():
        new_user = User(login_type=form.login_type.data, login=form.login.data,
                        emp_id=emp_id)
        new_user.set_password(form.password.data)
        db.session.add(new_user)
        db.session.commit()
        flash('Registration successful!')
        return redirect(url_for('login'))
    return render_template('login/register.html', form=form)

测试

base.py

from config import TestConfig
from app import app, db

@pytest.fixture
def client():
    """
    Initializes test requests for each individual test.  The test request
    keeps track of cookies.
    """
    app.config.from_object(TestConfig)

    client = app.test_client()
    ctx = app.app_context()
    ctx.push()

    yield client

    ctx.pop()


def confirm_bpm_login(client, group_name, username, password):
    """
    POST to /confirm
    """
    return client.post('/confirm', data=dict(
        group_name=group_name,
        username=username,
        password=password,
        submit=True
    ), follow_redirects=True)

test_auth.py

from app import db
from app.models import BPMCompany, BPMEmployee, User, BPMUser

from tests.base import client, db_data, login, confirm_bpm_login

def test_registration_page_from_confirm(client, db_data):
    """
    Test registration page by HTTP GET request  from "/confirm" url.
    Should cause redirect to registration page.

    !!! FAILING !!!
    Reason: The POST to /confirm will redirect us to /register?emp_id=1,
    but it will return the index.html because in the register view,
    request.referrer does not recognize the POST is coming from /confirm_bpm
    """
    bpm_user = BPMUser.query.filter_by(id=1).first()

    rv = confirm_bpm_login(client, bpm_user.group_name,
                           bpm_user.user_name, 'jsmith01')

    assert b'Register' in rv.data

db_data参数是 base.py 中的一个固定装置,它仅使用必要的数据填充数据库,以使注册流程正常工作。

我的目标是测试完整的注册流程,而不必将确认和注册分为两个测试。

1 个答案:

答案 0 :(得分:2)

在重定向之后,Flask测试客户端似乎没有添加Referer标头。

您可以做的是实现您自己的以下重定向版本。也许是这样的:

def confirm_bpm_login(client, group_name, username, password):
    """
    POST to /confirm
    """
    response = client.post('/confirm', data=dict(
        group_name=group_name,
        username=username,
        password=password,
        submit=True
    ), follow_redirects=False)
    if 300 <= response.status_code < 400:
        response = client.get(response.headers['Location'], headers={
            "Referer": 'http://localhost/confirm'
        })
    return response

请测试一下,我是从内存中写出来的,可能需要进行一些细微的调整。