摘要:當(dāng)功能越來(lái)越復(fù)雜的時(shí)候,你可能修改了一些東西,導(dǎo)致另外一個(gè)功能的不可用,而單元測(cè)試也能保證了原有功能被破壞后能被檢測(cè)出來(lái)。
前一篇講到了 TDD 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)的相關(guān)概念和環(huán)境搭建,這篇就著手開(kāi)始用TDD方式開(kāi)發(fā)了。首先這篇需要編寫(xiě)用戶相關(guān)的API接口,如用戶注冊(cè)、用戶登錄、用戶驗(yàn)證等功能。
編寫(xiě)測(cè)試這里使用 Python 自帶的測(cè)試框架 unittest 來(lái)編寫(xiě)簡(jiǎn)單測(cè)試,后續(xù)會(huì)使用更好用的 pytest 框架來(lái)完成整個(gè)網(wǎng)站的測(cè)試。
首先,最基本的測(cè)試是 Flask 應(yīng)用實(shí)例是否存在,新建一個(gè) test_basic.py 文件,當(dāng)前 v2ex 項(xiàng)目結(jié)構(gòu)如下:
├── LICENSE ├── Pipfile ├── Pipfile.lock ├── README.md └── tests ├── test_basic.py └── test_user.py
編寫(xiě) test_user.py 代碼如下:
import unittest from flask import current_app from server import create_app class UserTestCase(unittest.TestCase): def setUp(self): self.app = create_app("testing") self.app_context = self.app.app_context() self.app_context.push() def tearDown(self): self.app_context.pop() def test_app_is_exist(): """測(cè)試 Flask 實(shí)例是否存在""" self.assertFalse(current_app is None) if __name__ == "__main__": unittest.main()
這里使用 unittest 編寫(xiě)了一個(gè)測(cè)試類(lèi),setUp() 和 tearDown() 允許執(zhí)行每個(gè)測(cè)試用例前分別初始化和清理測(cè)試環(huán)境,setUp 可用于創(chuàng)建應(yīng)用實(shí)例,然后測(cè)試完成后就通過(guò) tearDown 函數(shù)清理.
很明顯,這個(gè)測(cè)試肯定是失敗的,因?yàn)楹苊黠@
from server import create_app
這一行是什么東東啊,好像項(xiàng)目里沒(méi)有存在啊,這就是 TDD 的一個(gè)概念了,先編寫(xiě)一個(gè)預(yù)料之中的失敗,然后一步步的把失敗那部分改進(jìn)到測(cè)試成功為止。
新建一個(gè) server 包,用于保存 v2ex 的業(yè)務(wù)邏輯代碼,下面是當(dāng)前項(xiàng)目的結(jié)構(gòu):
v2ex ├── LICENSE ├── Pipfile ├── Pipfile.lock ├── README.md ├── server │?? └── __init__.py └── tests ├── test_basic.py └── test_user.py
為了組織好模塊,會(huì)將多個(gè)模塊分為包。簡(jiǎn)單來(lái)說(shuō),包就是文件夾,但該文件夾下必須存在 __init__.py 文件, 然后可以在 __init__.py 文件中新增創(chuàng)建 Flask 實(shí)例的工廠函數(shù),代碼如下所示:
from flask import Flask from config import config def create_app(config_name: str): """ 工廠函數(shù),用于延遲創(chuàng)建 Flask 實(shí)例,可用于創(chuàng)建多個(gè)實(shí)例. :param config_name: 配置名稱(chēng),可根據(jù)開(kāi)發(fā)環(huán)境、測(cè)試環(huán)境、生產(chǎn)環(huán)境區(qū)分 :return: Flask 示例 """ app = Flask(__name__) app.config.from_object(config[config_name]) config[config_name].init_app(app) return app
然后運(yùn)行 tests 文件夾下的 test_basic.py 文件,
$ python3 tests/test_basic.py Ran 1 test in 0.007s FAILED (errors=1) Error Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 59, in testPartExecutor yield File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 611, in run self.setUp() File "/Users/guoweikuang/project/github/v2ex/tests/test_basic.py", line 14, in setUp self.app = create_app("testing") File "/Users/guoweikuang/project/github/v2ex/server/__init__.py", line 17, in create_app app.config.from_object(config[config_name]) NameError: name "config" is not defined
這還不能成功,因?yàn)槲覀儚淖铋_(kāi)始就說(shuō)過(guò),要使用最佳實(shí)踐方式來(lái)一步步實(shí)現(xiàn)網(wǎng)站,因此實(shí)例化 Flask 需要多帶帶存在一個(gè)配置模塊(config.py),目的就是把配置和其它功能區(qū)分開(kāi)。
而且 TDD 的思想就是每次編寫(xiě)最少量的代碼取得一些進(jìn)展,再運(yùn)行測(cè)試,如此不斷重復(fù),直到測(cè)試成功為止,最后可能還要重構(gòu)代碼,測(cè)試能保證不破壞任何一個(gè)功能。
當(dāng)前文件結(jié)構(gòu)如下:
v2ex ├── LICENSE ├── Pipfile ├── Pipfile.lock ├── README.md ├── config.py ├── server │?? └── __init__.py └── tests ├── test_basic.py └── test_user.py
前面一節(jié)已經(jīng)知道測(cè)試失敗原因,這一節(jié)就編寫(xiě)一個(gè)config.py 模塊使單元測(cè)試通過(guò):
class Config(object): """ 配置基類(lèi),所有其它配置類(lèi)都要繼承該類(lèi). """ @staticmethod def init_app(app): pass class DevelopmentConfig(Config): """ 開(kāi)發(fā)環(huán)境配置 """ DEBUG = True class ProductionConfig(Config): """ 生產(chǎn)環(huán)境配置 """ DEBUG = False class TestingConfig(Config): """ 測(cè)試環(huán)境配置 """ TESTING = True DEBUG = True config = { "development": DevelopmentConfig, "product": ProductionConfig, "testing": TestingConfig, "default": DevelopmentConfig, }
使用最少的代碼使測(cè)試成功,然后運(yùn)行 test_basic.py 看看測(cè)試是否通過(guò)
$ python tests/test_basic.py . ---------------------------------------------------------------------- Ran 1 test in 0.001s OK總結(jié)
從上面步驟可以總結(jié)到,先寫(xiě)測(cè)試代碼,然后設(shè)法使測(cè)試一步步通過(guò)的 TDD 開(kāi)發(fā)方式是十分有用的,保證了開(kāi)發(fā)的功能符合預(yù)期的想法。當(dāng)功能越來(lái)越復(fù)雜的時(shí)候,你可能修改了一些東西,導(dǎo)致另外一個(gè)功能的不可用,而單元測(cè)試也能保證了原有功能被破壞后能被檢測(cè)出來(lái)。這里的代碼都可以到 v2ex
項(xiàng)目中查看,每一篇文章都對(duì)應(yīng)著一個(gè) tag, 想要查看每篇文章的修改可以切到對(duì)應(yīng)標(biāo)簽上查看。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/42631.html
摘要:測(cè)試驅(qū)動(dòng)開(kāi)發(fā)簡(jiǎn)稱(chēng),是一種軟件開(kāi)發(fā)過(guò)程中的應(yīng)用方法,,由極限編程中倡導(dǎo),以其倡導(dǎo)先寫(xiě)測(cè)試程序,然后編碼實(shí)現(xiàn)其功能得名。測(cè)試驅(qū)動(dòng)著整個(gè)開(kāi)發(fā)過(guò)程首先,驅(qū)動(dòng)代碼的設(shè)計(jì)和功能的實(shí)現(xiàn)其后,驅(qū)動(dòng)代碼的再設(shè)計(jì)和重構(gòu)。 showImg(https://segmentfault.com/img/remote/1460000017081716); 前言 一直都有聽(tīng)到 TDD 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)的開(kāi)發(fā)方式,之前看...
摘要:前置條件這不是一個(gè)入門(mén)課程。此課程為至少有六個(gè)月網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn)的高級(jí)入門(mén)者設(shè)置。主題資源目標(biāo)這部分結(jié)束,具備以下能力。。。第一部分完整代碼依賴(lài)第一部分依賴(lài)耗時(shí)一章需要幾個(gè)小時(shí)到一整天??沼啻髩K時(shí)間來(lái)完成一章,特別是,,這些較難的部分。 在第一部分, 你學(xué)到如何使用 Docker 來(lái)創(chuàng)建一個(gè)基于python, postgres, 和 flask web 框架的 RESTful API 可重...
摘要:現(xiàn)在有了之后,部署方式變了更加容易,不容易出現(xiàn)配置錯(cuò)誤,環(huán)境不一致問(wèn)題。實(shí)際應(yīng)用中,經(jīng)常遇到多個(gè)容器相配合運(yùn)行一套應(yīng)用程序的情況。所以想要將應(yīng)用運(yùn)行在容器中,該容器必須將該應(yīng)用所有的環(huán)境依賴(lài)安裝好。 showImg(https://segmentfault.com/img/remote/1460000017081815); 背景 ??以前部署應(yīng)用,需要各種環(huán)境配置,各種shell操作...
摘要:現(xiàn)在有了之后,部署方式變了更加容易,不容易出現(xiàn)配置錯(cuò)誤,環(huán)境不一致問(wèn)題。實(shí)際應(yīng)用中,經(jīng)常遇到多個(gè)容器相配合運(yùn)行一套應(yīng)用程序的情況。所以想要將應(yīng)用運(yùn)行在容器中,該容器必須將該應(yīng)用所有的環(huán)境依賴(lài)安裝好。 showImg(https://segmentfault.com/img/remote/1460000017081815); 背景 ??以前部署應(yīng)用,需要各種環(huán)境配置,各種shell操作...
摘要:目前就職于,他在各種演講研討會(huì)和開(kāi)發(fā)者大會(huì)上積極推廣測(cè)試驅(qū)動(dòng)開(kāi)發(fā)。問(wèn)很多敏捷教練都表示訓(xùn)練新人做測(cè)試驅(qū)動(dòng)開(kāi)發(fā)是一件辛苦而進(jìn)度緩慢的事,并且收益也不是很大。首先是開(kāi)發(fā)的對(duì)話式風(fēng)格。第一個(gè)問(wèn)題就是測(cè)試套件的速度。 Harry J.W. Percival目前就職于PythonAnywhere,他在各種演講、研討會(huì)和開(kāi)發(fā)者大會(huì)上積極推廣測(cè)試驅(qū)動(dòng)開(kāi)發(fā)(TDD)。他在利物浦大學(xué)獲得計(jì)算機(jī)科學(xué)碩士學(xué)...
閱讀 1998·2021-11-23 09:51
閱讀 1445·2021-11-18 10:02
閱讀 1035·2021-10-25 09:44
閱讀 2169·2019-08-26 18:36
閱讀 1693·2019-08-26 12:17
閱讀 1227·2019-08-26 11:59
閱讀 2803·2019-08-23 15:56
閱讀 3432·2019-08-23 15:05