剛開始寫 Flask 專案時,常常都會擔心:「要是到上線前才出現 bug 怎麼辦?到時候會不會要全部重做?」其實只要加上一點單元測試,就能降低很多錯誤出現的機率
單元測試的重要性:可參考 Day12. 單元測試 (Unit Test),讓每個功能安心上路。
flask_sqlalchemy_demo/
│
├── app.py # Flask 主程式
├── models.py # 資料庫模型
├── tests/ # 單元測試在這裡呦!!
│ └── test_models.py # 用來檢查資料模型的正確性
├── templates/
│ ├── index.html # 顯示留言板
│ └── add_comment.html # 新增留言頁面
└── requirements.txt # 套件
為了讓開發之路更加順暢,不妨在一開始就建立虛擬環境,可以省去日後許多環境交錯的困惱。
python -m venv venv
source venv/bin/activate # Linux / Mac
source venv/Scripts/activate # Windows
# 安裝必要套件
pip install flask flask_sqlalchemy pytest
from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
import os
app = Flask(__name__)
# 定義資料庫路徑與配置
base_dir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(base_dir, 'data.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 建立 SQLAlchemy 物件
db = SQLAlchemy(app)
# 匯入模型
from models import Comment
@app.route('/')
def index():
comments = Comment.query.order_by(Comment.timestamp.desc()).all()
return render_template('index.html', comments=comments)
@app.route('/add', methods=['GET', 'POST'])
def add_comment():
if request.method == 'POST':
content = request.form.get('content')
if content:
new_comment = Comment(content=content)
db.session.add(new_comment)
db.session.commit()
return redirect(url_for('index'))
return render_template('add_comment.html')
if __name__ == '__main__':
with app.app_context():
db.create_all() # 建立資料庫與表格
app.run(debug=True)
from app import db
from datetime import datetime
class Comment(db.Model):
# 綁定的資料表名稱
__tablename__ = 'comments'
# 主key
id = db.Column(db.Integer, primary_key=True)
# 留言內容
content = db.Column(db.String(255), nullable=False)
# 留言時間
timestamp = db.Column(db.DateTime, default=datetime)
def __repr__(self):
return f'<Comment {self.content[:20]}>'
有了基本功能後,別忘記替 models 檔案安排個小小測試,請在 tests/test_models.py 新增以下程式碼:
import pytest
from app import db
from models import Comment
# 測試函式都以 test_ 開頭喔~~
def test_comment_create():
comment = Comment(content="單元測試留言")
# assert 的任務是:負責檢查結果正確與否
assert comment.content == "單元測試留言"
assert isinstance(comment.timestamp, type(comment.timestamp))
在專案根目錄,輸入:pytest
pytest 會自動執行一次小測試,檢查可能會出問題的地方。
測試未通過:
測試通過:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>留言板</title>
</head>
<body>
<h1>留言板</h1>
<a href="{{ url_for('add_comment') }}">新增留言</a>
<ul>
{% for comment in comments %}
<li>{{ comment.content }} <small>({{ comment.timestamp.strftime('%Y-%m-%d %H:%M') }})</small></li>
{% else %}
<li>目前沒有留言</li>
{% endfor %}
</ul>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>新增留言</title>
</head>
<body>
<h1>新增留言</h1>
<form action="{{ url_for('add_comment') }}" method="post">
<textarea name="content" rows="4" cols="50" placeholder="請輸入留言"></textarea><br>
<input type="submit" value="送出">
</form>
<a href="{{ url_for('index') }}">回留言板</a>
</body>
</html>
Ref.