後端框架之Flask--藍圖和測試單元
Blueprint
Blueprint概念:
簡單來說,Blueprint 是一個儲存操作方法的容器,這些操作在這個Blueprint 被註冊到一個應用之後就可以被呼叫,Flask 可以通過Blueprint來組織URL以及處理請求。
Flask使用Blueprint讓應用實現模組化,在Flask中,Blueprint具有如下屬性:
- 一個應用可以具有多個Blueprint
- 可以將一個Blueprint註冊到任何一個未使用的URL下比如 “/”、“/sample”或者子域名
- 在一個應用中,一個模組可以註冊多次
- Blueprint可以單獨具有自己的模板、靜態檔案或者其它的通用操作方法,它並不是必須要實現應用的檢視和函式的
- 在一個應用初始化時,就應該要註冊需要使用的Blueprint
但是一個Blueprint並不是一個完整的應用,它不能獨立於應用執行,而必須要註冊到某一個應用中。
初識藍圖
藍圖/Blueprint物件用起來和一個應用/Flask物件差不多,最大的區別在於一個 藍圖物件沒有辦法獨立執行,必須將它註冊到一個應用物件上才能生效
使用藍圖可以分為三個步驟
- 1,建立一個藍圖物件
admin=Blueprint('admin',__name__)
- 2,在這個藍圖物件上進行操作,註冊路由,指定靜態資料夾,註冊模版過濾器
@admin.route('/') def admin_home(): return 'admin_home'
- 3,在應用物件上註冊這個藍圖物件
app.register_blueprint(admin,url\_prefix='/admin')
BluePrint執行機制
- 藍圖是儲存了一組將來可以在應用物件上執行的操作,註冊路由就是一種操作
- 當在應用物件上呼叫 route 裝飾器註冊路由時,這個操作將修改物件的url_map路由表
- 然而,藍圖物件根本沒有路由表,當我們在藍圖物件上呼叫route裝飾器註冊路由時,它只是在內部的一個延遲操作記錄列表defered_functions中添加了一個項
- 當執行應用物件的 register_blueprint() 方法時,應用物件將從藍圖物件的 defered_functions 列表中取出每一項,並以自身作為引數執行該匿名函式,即呼叫應用物件的 add_url_rule() 方法,這將真正的修改應用物件的路由表
藍圖的url字首
- 當我們在應用物件上註冊一個藍圖時,可以指定一個url_prefix關鍵字引數(這個引數預設是/)
在應用最終的路由表 url_map中,在藍圖上註冊的路由URL自動被加上了這個字首,這個可以保證在多個藍圖中使用相同的URL規則而不會最終引起衝突,只要在註冊藍圖時將不同的藍圖掛接到不同的自路徑即可
url_for
url_for('admin.index') # /admin/
註冊靜態路由
和應用物件不同,藍圖物件建立時不會預設註冊靜態目錄的路由。需要我們在 建立時指定 static_folder 引數。
下面的示例將藍圖所在目錄下的static_admin目錄設定為靜態目錄
admin = Blueprint("admin",__name__,static_folder='static_admin')
app.register_blueprint(admin,url_prefix='/admin')
現在就可以使用/admin/static_admin/ 訪問static_admin目錄下的靜態檔案了 定製靜態目錄URL規則 :可以在建立藍圖物件時使用 static_url_path 來改變靜態目錄的路由。下面的示例將為 static_admin 資料夾的路由設定為 /lib
admin = Blueprint("admin",__name__,static_folder='static_admin',static_url_path='/lib')
app.register_blueprint(admin,url_prefix='/admin')
設定模版目錄
藍圖物件預設的模板目錄為系統的模版目錄,可以在建立藍圖物件時使用 template_folder 關鍵字引數設定模板目錄
admin = Blueprint('admin',__name__,template_folder='my_templates')
單元測試
測試的分類:
測試從軟體開發過程可以分為:
- 單元測試
- 對單獨的程式碼塊(例如函式)分別進行測試,以保證它們的正確性
- 整合測試
- 對大量的程式單元的協同工作情況做測試
- 系統測試
- 同時對整個系統的正確性進行檢查,而不是針對獨立的片段
在眾多的測試中,與程式開發人員最密切的就是單元測試,因為單元測試是由開發人員進行的,而其他測試都由專業的測試人員來完成。所以我們主要學習單元測試。
常用的斷言方法:assertEqual 如果兩個值相等,則pass
assertNotEqual 如果兩個值不相等,則pass
assertTrue 判斷bool值為True,則pass
assertFalse 判斷bool值為False,則pass
assertIsNone 不存在,則pass
assertIsNotNone 存在,則pass
登入測試演示程式碼:
被測試的程式碼如下:
@app.route('/login', methods=['POST'])
def login():
username = request.form.get('username')
password = request.form.get('password')
# 判斷引數是否為空
if not all([username, password]):
result = {
"errcode": -2,
"errmsg": "params error"
}
return jsonify(result)
# a = 1 / 0
# 如果賬號密碼正確
# 判斷賬號密碼是否正確
if username == 'person' and password == 'python':
result = {
"errcode": 0,
"errmsg": "success"
}
return jsonify(result)
else:
result = {
"errcode": -1,
"errmsg": "wrong username or password"
}
return jsonify(result)
單元測試程式碼:
import unittest
from flask import json
from demo2 import app
class LoginTestCase(unittest.TestCase):
def setUp(self):
app.testing = True
# 在執行測試的方法之前會呼叫的方法, 可以做一些初始化操作
self.client = app.test_client()
def tearDown(self):
pass
# 單元測試的方法要以test開頭
def test_empty_username_password(self):
response = app.test_client().post('/login', data={})
resp_data = response.data
json_dict = json.loads(resp_data)
print(json_dict)
self.assertIsNotNone(json_dict, '未獲取到返回資料')
self.assertIn('errcode', json_dict, '返回資料格式不正確')
errcode = json_dict.get('errcode')
self.assertEqual(errcode, -2, '返回的狀態碼錯誤')
def test_error_username_password(self):
response = app.test_client().post('/login', data={"username": "python", "password": "python"})
resp_data = response.data
json_dict = json.loads(resp_data)
print(json_dict)
self.assertIsNotNone(json_dict, '未獲取到返回資料')
self.assertIn('errcode', json_dict, '返回資料格式不正確')
errcode = json_dict.get('errcode')
self.assertEqual(errcode, -1, '返回的狀態碼錯誤')
def test_right_username_password(self):
response = app.test_client().post('/login', data={"username": "person", "password": "python"})
resp_data = response.data
json_dict = json.loads(resp_data)
print(json_dict)
self.assertIsNotNone(json_dict, '未獲取到返回資料')
self.assertIn('errcode', json_dict, '返回資料格式不正確')
errcode = json_dict.get('errcode')
self.assertEqual(errcode, 0, '返回的狀態碼錯誤')