Почему Flask-Mail действительно отправляет сообщения во время тестирования - PullRequest
2 голосов
/ 23 апреля 2019

В моем приложении есть следующий тест:

@pytest.mark.usefixtures('database')
def test_reset_email(client):
    assert current_app.config['TESTING']
    with mail.record_messages() as outbox:
        response = client.post('/reset', data=dict(email=tconst.ADMIN_EMAIL),
                               follow_redirects=True)
        msg = outbox[-1]
        assert const.RESET_PASSWORD_REQUEST_FLASH in str(response.data)
        assert msg.subject == const.RESET_EMAIL_SUBJECT
        assert 'Reset Password' in msg.html
        assert 'Reset Password' in msg.body
        pattern = ('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*'
                   + '\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+')  # noqa W605
        url = re.findall(pattern, msg.body)[0]
        path = urlparse(url).path
        response = client.post(path, data=dict(password='newpass'), follow_redirects=True)
        log_in(client, tconst.ADMIN_EMAIL, 'newpass')
        assert 'Logout' in str(response.data)

В соответствии с документацией, если app.config['TESTING'] равен True, электронные письма будут подавлены.Набор тестов пройден, но сообщение электронной почты фактически отправлено.

@user_blueprint.route('/reset', methods=['GET', 'POST'])
def reset():
    """Sends a tokenized email link to the user. Fails silently if email doesn't exist."""
    form = ResetPasswordForm()
    if form.validate_on_submit():
        email = form.email.data
        user = User.select_by_email(email=email).first()
        if user:
            timed_serializer = URLSafeTimedSerializer(current_app.config['SECRET_KEY'])
            token = timed_serializer.dumps(email, salt='recovery-token')
            url = url_for('user.reset_with_token', token=token, _external=True)
            body = render_template('email/recover.txt', url=url)
            html = render_template('email/recover.html', url=url)
            msg = Message(body=body, html=html, recipients=[email],
                          subject=const.RESET_EMAIL_SUBJECT)
            mail.send(msg)
        flash(const.RESET_PASSWORD_REQUEST_FLASH, 'success')
        return redirect(url_for('user.login'))
    return render_template('user/reset.html', form=form)

Я также попытался установить для MAIL_SUPPRESS_SEND в конфигурации приложения значение True (а также False, что не позволяет assert).

Что я делаю не так?

1 Ответ

0 голосов
/ 24 апреля 2019

Оказывается, ответ был в том, как я создавал приложение Flask. Приспособление pytest создало приложение, которое имело конфигурацию по умолчанию (т.е. производственную), что означает, что оно не было в тестовом режиме, когда был создан объект mail, а когда я обновлял конфигурацию после создания приложения, mail объект не знал об этом. Решением было передать create_app конфиг из устройства pytest.

def create_app(config=None):
    ...
    config = config or os.getenv('APP_SETTINGS', 'app.ProdConfig')
    app.config.from_object(config)
    ...

@pytest.fixture(scope='module')
def app():
    app = create_app(config='app.TestConfig')
    ...
...