测试用户邀请系统

时间:2015-10-22 23:36:10

标签: python unit-testing flask

我在Flask应用程序中构建了一个用户邀请系统,并希望使用Python unittest进行测试。我正在使用SendGrid发送电子邮件。如何在测试期间阻止SendGrid实际发送电子邮件?我可以收到用户邀请链接并将其拉入我的测试中吗?我的代码如下:

# views.py
@app.route('/add_user', methods=['GET', 'POST'])
@login_required
@groups_required(['site_admin'])
def add_user():
    """
    Send invite email with token to invited user
    """
    form = AddUserForm()

    if form.validate_on_submit():

        # token serializer
        ts = URLSafeTimedSerializer(app.config['SECRET_KEY'])

        email = request.form['email']
        tenant_id = user.custom_data['tenant_id']

        # create token containing email and tenant_id
        token = ts.dumps([email, tenant_id])

        # create url with token, e.g. /add_user_confirm/asdf-asd-fasdf
        confirm_url = url_for(
            'add_user_confirm',
            token=token,
            _external=True)

        try:
            # sendgrid setup
            sg = sendgrid.SendGridClient(
                app.config['SENDGRID_API_KEY'],
                raise_errors=True
            )

            # email setup
            message = sendgrid.Mail(
                to=request.form['email'],
                subject='Account Invitation',
                html='You have been invited to set up an account on PhotogApp. Click here: ' + confirm_url,
                from_email='support@photogapp.com'
            )

            # send email
            status, msg = sg.send(message)

            flash('Invite sent successfully.')
            return render_template('dashboard/add_user_complete.html')

        # catch and display SendGrid errors
        except SendGridClientError as err:
            flash(err.message.get('message'))
        except SendGridServerError as err:
            flash(err.message.get('message'))
    return render_template('dashboard/add_user.html', form=form)


@app.route('/add_user_confirm/<token>', methods=['GET', 'POST'])
def add_user_confirm(token):
    """
    Decode invite token and create new user account
    """
    form = RegistrationForm()
    decoded = None
    try:
        ts = URLSafeTimedSerializer(app.config['SECRET_KEY'])
        decoded = ts.loads(token, max_age=86400)
        email = decoded[0]
    except:
        abort(404)

    if form.validate_on_submit():
        try:
            tenant_id = decoded[1]

            data = {}
            data['email'] = email
            data['password'] = request.form['password']

            # given_name and surname are required fields
            data['given_name'] = 'Anonymous'
            data['surname'] = 'Anonymous'

            # set tenant id and site_admin status
            data['custom_data'] = {
                'tenant_id': tenant_id,
                'site_admin': 'False'
            }

            # create account
            account = User.create(**data)

            # add user to tenant group
            account.add_group(tenant_id)

            # login user
            login_user(account, remember=True)

            # success redirect
            return render_template('account/add_user_complete.html')
        except StormpathError as err:
            flash(err.message.get('message'))

    elif request.method == 'POST':
        flash("Passwords don't match.")

    return render_template('account/add_user_setpassword.html',
                           form=form,
                           email=email)

# tests.py
def test_add_user(self):
    resp = self.client.post('/add_user', data={
            'email': self.test_email
        }, follow_redirects=True)
assert 'User invitation sent' in resp.data

1 个答案:

答案 0 :(得分:1)

所以这是一个非常完美的模拟案例。模拟背后的基本思想是你用普通的传递,失败,副作用替换当前的功能(在这种情况下,发送电子邮件)。

If you're using Python 2.7 you'll have to download the mock third party package

否则你可以说

from unittest import mock

In this particular case I'd suggest using mock.patch

# tests.py
from unittest import mock

@mock.patch("sg.send") 
def test_add_user(self, mocked_send):
    mocked_send.return_value = None # Do nothing on send
    resp = self.client.post('/add_user', data={
            'email': self.test_email
        }, follow_redirects=True)
assert 'User invitation sent' in resp.data

这将使得当sg.send被调用时,它将调用模拟函数而不是实函数。由于默认情况下模拟是空白的,因此不会发送可怕的电子邮件。

注意SendGrid需要在test.py文件中导入并在范围内。