1. 程式人生 > >用flask開發個人部落格(40)—— Flask中三種測試方法

用flask開發個人部落格(40)—— Flask中三種測試方法

一、單元測試並統計測試的覆蓋率

1.1 Flask中的單元測試

        在之前的文章中介紹過在flask中進行單元測試的方法,目前我們的程式碼中存在下面的單元測試:

classBasicTestCase(unittest.TestCase):
    def Setup(self):
        self.app=create_app('testing')
        self.app_context=self.app.app_context()
        self.app_context.push()
        db.create_all()
 
    def teardown(self):
        db.session.remove()
        db.drop_all()
        self.app_context.pop()
 
    def test_app_exits(self):
        self.assertFalse(current_app is None)
 
    def test_app_is_testing(self):
       self.assertFalse(current_app.config['TESTING'])

        並且,我們在manager的命令列中增加了執行單元測試的命令:

@manager.command 
def test(): 
    """Run the unittests""" 
    import unittest 
   tests=unittest.TestLoader().discover('test') 
   unittest.TextTestRunner(verbosity=2).run(tests)

        可以通過命令列,按照下面的方式進行單元測試:

(flasky)[email protected]:~/Github/flaskTs$ python manager.py test
test_app_exits(test_basic.BasicTestCase) ... ok
test_app_is_testing(test_basic.BasicTestCase) ... ok
 
----------------------------------------------------------------------
Ran 2 tests in0.005s
 
OK
 

1.2 使用coverage進行單元測試覆蓋率的統計

        Flask中可以使用coverage模組來統計進行單元測試的程式碼覆蓋率,其安裝方式如下:

pip installcoverage

        安裝完成後,我們將coverage作為一個自定義命令的選項附加到test命令中:

COV=None
ifos.environ.get('COVERAGE'):
    import coverage
    COV=coverage.coverage(branch=True,include='*')
    COV.start()
 
@manager.command 
deftest(coverage=False): 
    """Run the unittests"""
    if coverage and notos.environ.get('COVERAGE'):
        import sys
        os.environ['COVERAGE']='1'
       os.execvp(sys.executable,[sys.executable]+sys.argv)
    import unittest 
   tests=unittest.TestLoader().discover('tests') 
   unittest.TextTestRunner(verbosity=2).run(tests) 
    if COV:
        COV.stop()
        COV.save()
        print('Coverage:')
        COV.report()
        COV.erase()

        首先在全域性的範圍內,我們先檢查是否具有'COVERAGE'環境變數,如果定義了該變數,就利用coverage的coverage函式構造一個coverage物件COV。coverage函式有兩個引數,第一個引數branch設定為True表示檢查的模組包含指定目錄下的子目錄,而第二個引數include是在指定目錄,設定成’*’的意思就是設定當前目錄和當前目錄下的模組位檢查模組。

        而在test()函式中,附加的命令列引數coverage會作為test()函式的一個bool型別的引數,如果命令列附加了該引數,coverage將會等於True。在函式內部,先判斷是否coverage已經是否定義了'COVERAGE'環境變數。因為我們定義以及執行COV的程式碼為全域性程式碼,在執行test命令列之前已經執行過,所以在判斷完之後,呼叫了os.execvp重新執行了程式。接下來COV變數不再是None,就可進行if COV後面的操作。

        執行的程式結果如下,由於將當前目錄下以及子目錄下所有的模組都作為了統計物件,所以結果中包含了flask本身自帶的一些模組。


二、使用Flask Web測試客戶端進行測試   

        Flask中的成員函式test_client()可以返回一個客戶端物件,可以模擬Web客戶端,用來同Web服務端進行互動。它可以測試Web程式,也可以用來測試Rest API,下面就該客戶端的使用進行討論。

2.1 測試Web程式

        新建一個FlaskClientTest單元測試類如下:

classFlaskClientTest(unittest.TestCase):
    def setUp(self):
        self.app=create_app('testing')
        self.app_context=self.app.app_context()
        self.app_context.push()
        db.create_all()
        self.client=self.app.test_client()
   
    def tearDown(self):
        db.session.remove()
        db.drop_all()
        self.app_context.pop()
   
    def test_home_page(self):
        response=self.client.get(url_for('main.index'))
        self.assertTrue('Home' inresponse.get_data(as_text=True))
   
    def test_register(self):
       response=self.client.post(url_for('main.register'),data={
            'email':'[email protected]',
            'name':'Hyman',
            'password1':'123',
            'password2':'123'})
       self.assertTrue(response.status_code==302)

        test_home_page是用來進行測試主頁的測試用例,這裡使用self.client.get(url_for('main.index'))的方法,使用GET方法訪問相應的url,並獲取響應結果。然後呼叫response的get_data()獲取響應結果,這裡面設定as_text=True,會把結果格式化成一個字串,進而判斷‘Home’是否在這個字串中。

        test_register用來模擬註冊使用者過程,對註冊的路由進行測試。這裡採用了POST的方法傳送了一個表單,而data中是對錶單各個欄位的賦值,這裡面的key值一定要和我們定義的登錄檔單的欄位名稱一致。由於註冊路由最終向主頁進行了重定向,屆時服務端回返回給瀏覽器302的狀態碼,我們通過判斷響應的status_code是否是302而判斷測試是否通過。

2.2 測試Rest API

        接下來,測試下上篇文章編寫的一個用來增加新部落格的Rest API:

deftest_posts(self):
        response=self.client.post(
            url_for('main.new_post'),
            data=json.dumps({'body':'I am a newpost'}),
            content_type='application/json')
       self.assertTrue(response.status_code==200)

        這裡面需要注意的就是,測試Rest API時需要在client的post方法中顯示的指定傳送的資料型別content_type為'application/json',而且傳送的data需要用json.dumps()方法將資料格式化成json的格式。assertTrue中還是檢驗響應的status_code,如果文章建立成功,服務端會返回200的狀態碼,所以在這裡同200進行了比較。

三、使用selenium進行自動化測試

        Selenium可以自動啟動瀏覽器,模擬使用者點選瀏覽器的連線,selenium的安裝方法如下:

pip install selenium

        我們進行測試的思路時,利用後臺執行緒啟動服務端,然後在主執行緒中利用selenium自動操作firefox進行自動化的測試。在使用selenium之前,我們先要定義一個路由可以關閉服務端的執行,以使在測試結束後服務端自動結束執行。

@main.route('/shutdown')
defserv_shutdown():
   shutdown=request.environ.get('werkzeug.server.shutdown')
    shutdown()
    return 'shuting down'

         werkzeug伺服器提供了一個shutdown函式供外部使用,在上述的檢視函式中,我們獲取到了這個函式,並進行呼叫,這樣通過訪問http://localhost:5000/shutdown這個url我們就可以實現關閉服務端。

        接下來是使用selenium進行自動化測試的程式碼:

#coding:utf-8
import unittest
from flaskimport current_app,url_for,json
from app importcreate_app,db
from seleniumimport webdriver
 
classSeleniumTestCase(unittest.TestCase):
    client=None
    @classmethod
    def setUpClass(cls):
        #啟動firefox
        try:
            cls.client=webdriver.Firefox()
        except:
            pass
        if cls.client:
            cls.app=create_app('testing')
           cls.app_context=cls.app.app_context()
            cls.app_context.push()
            db.create_all()
           threading.Thread(target=cls.app.run).start()
    @classmethod
    def tearDownClass(cls):
        if cls.client:
           cls.client.get('http://localhost:5000/shutdown')
            cls.client.close()
            db.drop_all()
            db.session.remove()
            cls.app_context.pop()
 
    def setUp(self):
        if not self.client:
            self.skipTest('Firefox isinvailable')
   
    def tearDown(self):
        pass
   
    def test_home_page(self):
       self.client.get('http://localhost:5000/')
        self.assertTrue(re.search('Home',self.client.page_source))

        通過修飾器classmethod定義了setUpClass()和tearDownClass()兩個成員函式,分別在該類中的所有的測試用例執行之前和之後執行,而setUp()和tearDown()是在每個測試用例執行前後都執行。在setUpClass()中,通過webdriver.Firefox()獲取到了Firefox()瀏覽器物件,並在threading.Thread(target=cls.app.run).start()中在後臺執行緒執行服務端,然後在測試用例test_home_page中我們通過這個瀏覽器物件訪問'http://localhost:5000/',並利用正則表示式判斷返回的結果中是否包含'Home'字串。在所有的測試完成之後,在tearDownClass()中訪問'http://localhost:5000/shutdown'從而完成了服務端的關閉。至此,一個完整的selenium測試流程完成。

        Selenium的強大在於,它可以操作瀏覽器實現自動化的測試,彷彿就像有人在瀏覽器上點選一樣,它建立的Firefox客戶端物件提供了很多方法可以在Web介面找到相關的元素並進行後續的操作。比如find_element_by_link_text()方法,可以根據超連結的名稱找到該連結,並在呼叫其Click()方法模擬點選超連結;find_element_by_name()方法根據根據名字找到對應的欄位,然後可以使用期send_keys()的方法在各個欄位中填入值。

Github位置:
https://github.com/HymanLiuTS/flaskTs
克隆本專案:
Git clone Git@github.com:HymanLiuTS/flaskTs.Git
獲取本文原始碼:
Git checkout FL40

相關推薦

flask開發個人部落40—— Flask測試方法

一、單元測試並統計測試的覆蓋率 1.1 Flask中的單元測試         在之前的文章中介紹過在flask中進行單元測試的方法,目前我們的程式碼中存在下面的單元測試: classBasicTestCase(unittest.TestCase): def Set

flask開發個人部落28—— 利用unittest進行單元測試

下面分析下這個webapp的單元測試模組test,請先看下目前test下的檔案結構:        目前__init__.py檔案還是空,請檢視test_basic.py的程式碼: import unittest from flask impor

flask開發個人部落24—— flask使用Flask_Mail傳送電子郵件

        flask中使用Flask-Mail提供對電子郵件的支援,下面將分步驟測試flask中傳送電子郵件的功能: 1 配置SMTP伺服器的資訊         我們需要藉助flask程式例項app的config屬性來配置電子郵件的SMTP伺服器資訊,其中主要的配置

flask開發個人部落8—— flask的模板

        一般而言,檢視函式中存在兩種邏輯,業務邏輯和表現邏輯。業務邏輯諸如我們在登入頁面時輸入使用者名稱和密碼後,點選確定按鈕時,在資料庫驗證該使用者名稱和密碼是否正確. 表現邏輯就是返回正確

flask開發個人部落4—— flask4全域性變數

一  current_app         current_app代表當前的flask程式例項,使用時需要flask的程式上下文啟用,我們以本專欄第一篇文章中寫的test.py為例介紹下它的用法: 1.1 啟用程式上下文 >>> from test i

flask開發個人部落5——flask的四響應型別

        在之前的程式碼中,檢視函式都返回了一個字串,在實際的開發中其返回的html檔案內容,本質其實也是字串。下面總結下flask中可以作為響應的幾種方法。 1、響應字串。         這個在前面已經說明過,但是需要指出的是,其實每次檢視函式在響應時還可以附帶狀

flask開發個人部落10—— Jinja2模板的控制結構

一 引言         模板,就是認為建立的一套用來管理資料的規則.其實從程式設計的角度來說,我們所使用的程式語言也可以理解成為一種模板的語言,而對應的程式語言檔案就是模板檔案,如cpp,py,cs檔案等等.最近我們做專案,用word做了一套模板,也是類似.既然類似程式語

flask開發個人部落6—— 為flask程式新增命令列直譯器

一 引入Manager         使用flask的方便之處在於可以使用大量的擴充套件功能,如資料庫和使用者認證都是通過擴充套件功能實現。打算開啟flask時支援命令列選項,我們需要引入flask-script擴充套件。 from flask_script import

flask開發個人部落36—— 使用SQLAlchemy對部落文章進行分頁

        我們在瀏覽某個部落格網站時,如果部落格文章過多,往往都進行了分頁顯示,比如CSDN中個人部落格的首頁顯示。在flask中SQLAlchemy不但可以進行資料建模和資料查詢等等,由於其支援分頁查詢,我們還可以利用其對我們的文章進行分頁。 一、建立部落格資料模型

flask開發個人部落1—— 一個簡單的flask程式

1、建立flask程式例項 from flask import Flask app=Flask(__name__)         Flask接受一個字串作為引數,這個引數決定程式的根目錄,以便於能找到相對於程式根目錄的資原始檔的位置,通常這種情況下都使用  __nam

flask開發個人部落32—— 進行表單欄位的驗證

一、引言         本文主要討論FlaskForm中各個表單欄位的限制方法。我們在定義表單物件時,往往需要處理很多細節功能,諸如限制欄位的長度,填寫的email要符合格式等等。FlaskForm中提供了很多限制表單欄位的方法。下面,我們將提供幾種常用的方法進行討論。

flask搭建個人部落——骨架、資料庫

編寫骨架程式: manage.py config.py app/main/__init__.py app/auth/__init__.py app/email.py app/models.py 設計資料庫models: 簡單的建立四個table:roles,users,c

Flask開發部落Flask-模板

作者:chen_h 微訊號 & QQ:862251340 微信公眾號:coderpai 目錄 上節回顧 如果你依照上一章的話,你應當有一個完全工作的簡單的 web 應用程式,我們專案的檔案結構如下(前

基於ssm框架的個人部落5--Dao層設計及測試

前臺的頁面完成了一部分,那麼是時候開發Dao層了,前面我們提到了mybatis的逆向工程,也展示了一些逆向生成的一些配置檔案,實體類......現在我們就基於ssm框架,對Dao進行開發,由於程式碼比較簡單,在此不做解釋,直接看註釋。 貼上程式碼 package test

使用GitHub + Hexo搭建個人部落- 安裝

最近在同事那瞭解到,使用GitHub + Hexo可以搭建自己的個人部落格,很早之前就想自己搞個網站做部落格,由於種種原因一直沒有實現 現在可以使用開源的工具搞個部落格還是蠻不錯的,這裡和大家分享下。 1. Hexo簡介 GitHub的簡單介紹,大家可以參考我前面的部落格,

搭建個人部落論壇的建議

        相信不少人希望搭建自己的部落格或者論壇作為自己的一個程式程式碼或者學習記錄存放的地方,還有可能地話就是弄一些比較有意義的論壇方便大家交流。博主給大家一些個人建議,僅供參考。         對於搭建個人部落格和論壇,我們比較熟悉的是discuz和wordpr

從CSDN個人主頁進入個人部落專欄

對這個問題本身感到很無語,但確實這個設計不太人性化。 解決: 1.進入個人主頁 2.將滑鼠移動到右上角的標誌上,出現,點選“部落格” 3.進入到新頁面後,點選我的部落格 4.不要捉急,馬上就成功了,進入新頁面後,再點選“我的部落格”(無語) 5.終於進入了夢寐以

使用github搭建個人部落初級

不能再初的初級版了,我保證!!我也是百度跟著別的大大的步驟一步步來的,寫到部落格記錄下,免得以後忘記。 步驟: 1、登入賬號後,點選下圖按鈕,新建倉庫。 2、填寫倉庫的屬性,倉庫名格式:你的github使用者名稱.github.io, 個人部落格簡介和描述檔

基於windows平臺Git+GitHub+Hexo搭建個人部落

之前最開始是瞭解並搭建的jekyll框架,然後又從網上百度了一下,很多部落格都支援Hexo,覺得Hexo更好用一些,也有很多支援jekyll的,自己確實不知道是jekyll和Hexo哪個更好用一些,所以又搭建了一下Hexo的環境。 我在這裡對我自己的操作步驟

使用node.js搭建簡易的個人部落

node.js和express應用框架的啟動 首先需要在電腦上安裝node.js的開發環境,安裝好之後,就可以使用它了。這裡我使用的開發工具是webStorm,然後使用 npm install --save express命令來安裝express模組;