unit testing framework

This commit is contained in:
Miguel Grinberg 2012-12-16 00:32:38 -08:00
parent d8e9bfe8bd
commit 8c091d7add
10 changed files with 140 additions and 7 deletions

View File

@ -3,7 +3,7 @@ from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.login import LoginManager from flask.ext.login import LoginManager
from flask.ext.openid import OpenID from flask.ext.openid import OpenID
from config import basedir from config import basedir, ADMINS, MAIL_SERVER, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD
app = Flask(__name__) app = Flask(__name__)
app.config.from_object('config') app.config.from_object('config')
@ -13,5 +13,25 @@ lm.setup_app(app)
lm.login_view = 'login' lm.login_view = 'login'
oid = OpenID(app, os.path.join(basedir, 'tmp')) oid = OpenID(app, os.path.join(basedir, 'tmp'))
if not app.debug:
import logging
from logging.handlers import SMTPHandler
credentials = None
if MAIL_USERNAME or MAIL_PASSWORD:
credentials = (MAIL_USERNAME, MAIL_PASSWORD)
mail_handler = SMTPHandler((MAIL_SERVER, MAIL_PORT), 'no-reply@' + MAIL_SERVER, ADMINS, 'microblog failure', credentials)
mail_handler.setLevel(logging.ERROR)
app.logger.addHandler(mail_handler)
if not app.debug:
import logging
from logging.handlers import RotatingFileHandler
file_handler = RotatingFileHandler('tmp/microblog.log', 'a', 1 * 1024 * 1024, 10)
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)
app.logger.info('microblog startup')
from app import views, models from app import views, models

View File

@ -1,5 +1,6 @@
from flask.ext.wtf import Form, TextField, BooleanField, TextAreaField from flask.ext.wtf import Form, TextField, BooleanField, TextAreaField
from flask.ext.wtf import Required, Length from flask.ext.wtf import Required, Length
from app.models import User
class LoginForm(Form): class LoginForm(Form):
openid = TextField('openid', validators = [Required()]) openid = TextField('openid', validators = [Required()])
@ -8,3 +9,20 @@ class LoginForm(Form):
class EditForm(Form): class EditForm(Form):
nickname = TextField('nickname', validators = [Required()]) nickname = TextField('nickname', validators = [Required()])
about_me = TextAreaField('about_me', validators = [Length(min = 0, max = 140)]) about_me = TextAreaField('about_me', validators = [Length(min = 0, max = 140)])
def __init__(self, original_nickname, *args, **kwargs):
Form.__init__(self, *args, **kwargs)
self.original_nickname = original_nickname
def validate(self):
if not Form.validate(self):
return False
if self.nickname.data == self.original_nickname:
return True
user = User.query.filter_by(nickname = self.nickname.data).first()
if user != None:
self.nickname.errors.append('This nickname is already in use. Please choose another one.')
return False
return True

View File

@ -12,7 +12,19 @@ class User(db.Model):
posts = db.relationship('Post', backref = 'author', lazy = 'dynamic') posts = db.relationship('Post', backref = 'author', lazy = 'dynamic')
about_me = db.Column(db.String(140)) about_me = db.Column(db.String(140))
last_seen = db.Column(db.DateTime) last_seen = db.Column(db.DateTime)
@staticmethod
def make_unique_nickname(nickname):
if User.query.filter_by(nickname = nickname).first() == None:
return nickname
version = 2
while True:
new_nickname = nickname + str(version)
if User.query.filter_by(nickname = new_nickname).first() == None:
break
version += 1
return new_nickname
def is_authenticated(self): def is_authenticated(self):
return True return True

7
app/templates/404.html Normal file
View File

@ -0,0 +1,7 @@
<!-- extend base layout -->
{% extends "base.html" %}
{% block content %}
<h1>File Not Found</h1>
<p><a href="{{url_for('index')}}">Back</a></p>
{% endblock %}

8
app/templates/500.html Normal file
View File

@ -0,0 +1,8 @@
<!-- extend base layout -->
{% extends "base.html" %}
{% block content %}
<h1>An unexpected error has occurred</h1>
<p>The administrator has been notified. Sorry for the inconvenience!</p>
<p><a href="{{url_for('index')}}">Back</a></p>
{% endblock %}

View File

@ -8,7 +8,12 @@
<table> <table>
<tr> <tr>
<td>Your nickname:</td> <td>Your nickname:</td>
<td>{{form.nickname(size = 24)}}</td> <td>
{{form.nickname(size = 24)}}
{% for error in form.errors.nickname %}
<br><span style="color: red;">[{{error}}]</span>
{% endfor %}
</td>
</tr> </tr>
<tr> <tr>
<td>About yourself:</td> <td>About yourself:</td>

View File

@ -16,7 +16,16 @@ def before_request():
g.user.last_seen = datetime.utcnow() g.user.last_seen = datetime.utcnow()
db.session.add(g.user) db.session.add(g.user)
db.session.commit() db.session.commit()
@app.errorhandler(404)
def internal_error(error):
return render_template('404.html'), 404
@app.errorhandler(500)
def internal_error(error):
db.session.rollback()
return render_template('500.html'), 500
@app.route('/') @app.route('/')
@app.route('/index') @app.route('/index')
@login_required @login_required
@ -94,7 +103,7 @@ def user(nickname):
@app.route('/edit', methods = ['GET', 'POST']) @app.route('/edit', methods = ['GET', 'POST'])
@login_required @login_required
def edit(): def edit():
form = EditForm() form = EditForm(g.user.nickname)
if form.validate_on_submit(): if form.validate_on_submit():
g.user.nickname = form.nickname.data g.user.nickname = form.nickname.data
g.user.about_me = form.about_me.data g.user.about_me = form.about_me.data
@ -102,7 +111,7 @@ def edit():
db.session.commit() db.session.commit()
flash('Your changes have been saved.') flash('Your changes have been saved.')
return redirect(url_for('edit')) return redirect(url_for('edit'))
else: elif request.method != "POST":
form.nickname.data = g.user.nickname form.nickname.data = g.user.nickname
form.about_me.data = g.user.about_me form.about_me.data = g.user.about_me
return render_template('edit.html', return render_template('edit.html',

View File

@ -12,4 +12,13 @@ OPENID_PROVIDERS = [
{ 'name': 'MyOpenID', 'url': 'https://www.myopenid.com' }] { 'name': 'MyOpenID', 'url': 'https://www.myopenid.com' }]
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'app.db') SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'app.db')
SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository') SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository')
# mail server settings
MAIL_SERVER = 'localhost'
MAIL_PORT = 25
MAIL_USERNAME = None
MAIL_PASSWORD = None
# administrator list
ADMINS = ['you@example.com']

3
runp.py Executable file
View File

@ -0,0 +1,3 @@
#!flask/bin/python
from app import app
app.run(debug = False)

42
tests.py Executable file
View File

@ -0,0 +1,42 @@
#!flask/bin/python
import os
import unittest
from config import basedir
from app import app, db
from app.models import User
class TestCase(unittest.TestCase):
def setUp(self):
app.config['TESTING'] = True
app.config['CSRF_ENABLED'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'test.db')
db.create_all()
def tearDown(self):
db.drop_all()
def test_avatar(self):
# create a user
u = User(nickname = 'john', email = 'john@example.com')
avatar = u.avatar(128)
expected = 'http://www.gravatar.com/avatar/d4c74594d841139328695756648b6bd6'
assert avatar[0:len(expected)] == expected
def test_make_unique_nickname(self):
# create a user and write it to the database
u = User(nickname = 'john', email = 'john@example.com')
db.session.add(u)
db.session.commit()
nickname = User.make_unique_nickname('john')
assert nickname != 'john'
# make another user with the new nickname
u = User(nickname = nickname, email = 'susan@example.com')
db.session.add(u)
db.session.commit()
nickname2 = User.make_unique_nickname('john')
assert nickname2 != 'john'
assert nickname2 != nickname
if __name__ == '__main__':
unittest.main()