1. 程式人生 > >後端框架之Flask--藍圖和測試單元

後端框架之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, '返回的狀態碼錯誤')