mercredi 29 juillet 2020

Testing multiple requests in single test method not working

I am trying to test signup form of my application. If same email or phone is used again, the request should be rejected. However, when firing multiple requests in a single method, the second request doesn't seem to get executed. My code

signup code

@user.route('/signup', methods=['GET', 'POST'])
@anonymous_required()
def signup():
    form = SignupForm()
    return_code = 200
    if form.validate_on_submit():
        if not User.find_by_email(form.email.data) and not User.find_by_phone(form.phone.data):
            usr = User()

            form.populate_obj(usr)
            usr.password = request.form.get('password')
            usr.alternate_id = int(time())
            usr.save()

            if login_user(usr):
                usr.update_activity_tracking(request.remote_addr)
                # flash('Thanks for signing up!')
                return redirect(url_for('user.welcome'))
        else:
            flash('The email or phone is already registered')
            return_code = 409
    else:
        return_code = 200 if request.method == 'GET' else 400

    return render_template('user/signup.html', form=form), return_code

Test code

@pytest.mark.usefixtures('empty_db')
def test_multiple_requests_failing(client, user):
    resp_one = client.post(url_for('user.signup'), data=user)

    assert resp_one.status_code == 302 # due to redirection
    assert User.query.count() == 1

    resp_two = client.post(url_for('user.signup'), data=user)
    assert resp_two.status_code == 409 # failing here. status code is still 302

    response_html = resp_two.data.decode('utf-8')
    assert 'The email or phone is already registered' in response_html

Fixture code

I am using pytest with pytest-flask plugin. However, I did try the same thing using naive test_client as well. I will post a case of that as well if required. The client fixture is provided by pytest itself.

@pytest.fixture(scope="session", autouse=True)
def app(tmpdir_factory):
    db_temp_dir = tmpdir_factory.mktemp('db_temp_dir')
    db_temp_path = os.path.abspath(os.path.join(db_temp_dir, 'test-db.sqlite'))
    db_uri = f'sqlite:///{db_temp_path}'

    override_settings = {
        'TESTING': True,
        'WTF_CSRF_ENABLED': False,
        'SQLALCHEMY_DATABASE_URI': db_uri
    }

    _app = create_app(settings_override=override_settings)

    ctx = _app.app_context()
    ctx.push()

    db.drop_all()
    db.create_all()

    yield _app

    ctx.pop()

@pytest.fixture()
def empty_db():
    meta = db.metadata
    for table in reversed(meta.sorted_tables):
        db.session.execute(table.delete())
    db.session.commit()

@pytest.fixture(scope="session")
def user():
    return dict(
        first_name='siddharth',
        last_name='gupta',
        email='check.sid@gmail.com',
        phone='1234123412',
        dob_date='12',
        dob_month='12',
        dob_year='1997',
        password='something',
        confirm_password='something',
        gender='male'
    )

I tried placing debugger on my application code. It turns out that the application code is called only on the first request and not on the second one. That clearly explains why the error is coming. But I don't understand how is resp_two getting the values that are present in resp_one and also the main thing of why the second request is not having any effect and is not getting called. I have a feeling that it might be related to the request context and application context being in scope but I am not sure. Please help. Thanks for taking the time.

Aucun commentaire:

Enregistrer un commentaire