這篇文章給大家分享的是有關(guān)在Django下如何測(cè)試與調(diào)試REST API的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。
目前創(chuàng)新互聯(lián)已為上千的企業(yè)提供了網(wǎng)站建設(shè)、域名、雅安服務(wù)器托管、綿陽(yáng)服務(wù)器托管、企業(yè)網(wǎng)站設(shè)計(jì)、紹興網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。對(duì)于大多數(shù)研發(fā)人員來(lái)說(shuō),都期望能找到一個(gè)良好的測(cè)試/調(diào)試方法,來(lái)提高工作效率和快速解決問(wèn)題。所謂調(diào)試,偏重于對(duì)某個(gè)bug的查找、定位、修復(fù);所謂測(cè)試,是檢驗(yàn)?zāi)硞€(gè)功能是否達(dá)到預(yù)期效果。測(cè)試發(fā)現(xiàn)問(wèn)題后進(jìn)行調(diào)試,從而解決問(wèn)題。
對(duì)于后臺(tái)研發(fā)來(lái)說(shuō),往往沒(méi)有客戶端研發(fā)(Windows/Android等等)那樣簡(jiǎn)單有效的DEBUG方法,比如Step by Step。雖然目前有很多IDE可以實(shí)現(xiàn)本地調(diào)試,但是因?yàn)楹笈_(tái)研發(fā)的環(huán)境復(fù)雜,你很難在一臺(tái)機(jī)器上模擬所有的環(huán)境,比如線上的數(shù)據(jù)庫(kù)只能在內(nèi)網(wǎng)訪問(wèn)等等,所以很多時(shí)候需要在服務(wù)器(DEV/STG/PROD)上進(jìn)行調(diào)試和測(cè)試工作。本文嘗試介紹一些Django Web服務(wù)下調(diào)試/測(cè)試REST API的方法,因?yàn)槭欠椒?,那自然仁者?jiàn)仁智者見(jiàn)智,所以也許你覺(jué)得會(huì)有用,也許會(huì)覺(jué)得毫無(wú)道理。
首先要說(shuō)的是,在服務(wù)器環(huán)境,針對(duì)Django Web服務(wù),print log是最簡(jiǎn)單有效的方法。python的語(yǔ)言特性決定了你可以隨時(shí)添加log,重新run一下就可以看到結(jié)果。本文接下來(lái)要說(shuō)的,并不是什么超脫于pring log的超級(jí)技巧,而是如何編寫代碼、利用工具進(jìn)行有效的調(diào)試/測(cè)試工作,并盡量做到減少重復(fù)性工作。
對(duì)于任何一個(gè)REST API來(lái)說(shuō),需要進(jìn)行測(cè)試的內(nèi)容包括兩部分:請(qǐng)求中的各個(gè)功能模塊是否正常、整個(gè)請(qǐng)求是否正常。對(duì)于研發(fā)人員來(lái)說(shuō),寫完代碼后當(dāng)然要進(jìn)行一番測(cè)試來(lái)確認(rèn)代碼是否正常工作、是否符合需求。這時(shí),有人選擇先測(cè)試一下整個(gè)請(qǐng)求是否正常,如果正常就萬(wàn)事大吉,交付給測(cè)試同事測(cè)試了,如果不正常則進(jìn)一步查看是哪個(gè)功能模塊出現(xiàn)問(wèn)題;有人選擇先逐一測(cè)試各個(gè)功能模塊是否正常,在確保各功能模塊正常后,再進(jìn)一步測(cè)試整個(gè)請(qǐng)求是否正常,然后交付測(cè)試。這兩種行事風(fēng)格并沒(méi)有特別的利弊之說(shuō),最好是在不同的情形下選擇使用,比如對(duì)于簡(jiǎn)單的功能API,可以使用第一種,而對(duì)于復(fù)雜的功能API,選擇第二種。不管行事風(fēng)格如何,都會(huì)涉及都前面所述的兩部分測(cè)試內(nèi)容,即分與合的兩部分測(cè)試。Django下,常見(jiàn)的有這么兩種方法,或者說(shuō)目前在我們項(xiàng)目組使用最廣泛的兩種方法:
1. 對(duì)于功能模塊,使用python manage.py shell來(lái)進(jìn)行調(diào)試與測(cè)試。該命令幫助我們啟動(dòng)一個(gè)python 的shell環(huán)境,并自動(dòng)加載了Django的上下文信息,我們可以在里面import任何函數(shù)和類,構(gòu)建參數(shù),調(diào)試/測(cè)試其相關(guān)的功能。如果需要定位問(wèn)題,一種方法是在源文件中加入更多的log,一種方法是將該功能模塊逐行敲一遍,看看在哪邊出現(xiàn)了問(wèn)題。
2. 對(duì)于整個(gè)請(qǐng)求,使用工具curl(linux下)或者Advanced REST Client(Windows下,Chome的一個(gè)插件)來(lái)構(gòu)建一個(gè)Request,發(fā)送給后臺(tái)服務(wù)。筆者使用更多的是第二個(gè),其可以構(gòu)建各個(gè)Method的Request,并且可以保存相應(yīng)的請(qǐng)求,還可以分享你保存的列表給別人使用。發(fā)送請(qǐng)求后,通過(guò)后臺(tái)log來(lái)查看請(qǐng)求是否正常及相關(guān)的異常錯(cuò)誤問(wèn)題,你可以使用tail -f /var/log/test.log來(lái)查看動(dòng)態(tài)log信息。
在合適的位置增加規(guī)范化的log對(duì)于后臺(tái)服務(wù)來(lái)說(shuō),是一件非常重要的事情,能幫助我們?cè)诰€上環(huán)境及時(shí)發(fā)現(xiàn)問(wèn)題,log的書(shū)寫應(yīng)該包括相應(yīng)的Tag,ErrorCode等等信息,方便查找。
上述兩個(gè)方法,可以很好的對(duì)Django下的Web服務(wù)進(jìn)行調(diào)試/測(cè)試,但是卻有著一些缺憾。對(duì)應(yīng)第一種方法,通過(guò)python manage.py shell進(jìn)行功能測(cè)試,意味著每次都需要啟動(dòng)一個(gè)shell,每次都需要將相應(yīng)的代碼敲一遍,存在著重復(fù)性的工作,其實(shí)這種方法更適用于應(yīng)對(duì)特殊的CASE,而不是針對(duì)Common的功能進(jìn)行調(diào)試/測(cè)試。對(duì)于第二種方法,首先,當(dāng)你想增加一些log時(shí),你需要重啟一下服務(wù)才能生效,而這種情況在生產(chǎn)環(huán)境就比較棘手;其次,通過(guò)這種方法進(jìn)行測(cè)試,你沒(méi)有辦法在程序中處理一些Response的結(jié)果。
Python和Django自帶了一些測(cè)試框架和工具,而充分利用這些,正好可以解決上述兩種方法的缺憾。常用的一些測(cè)試框架和工具有:
1)單元測(cè)試框架TestCase;
2)Django的Test Client,類似curl的工具,是一個(gè)類似內(nèi)置瀏覽器的工具,可以發(fā)起一個(gè)請(qǐng)求,并拿到對(duì)應(yīng)的response內(nèi)容;
3)RequestFactory,允許構(gòu)建一個(gè)request參數(shù),實(shí)現(xiàn)象調(diào)用函數(shù)一樣調(diào)用一個(gè)view的請(qǐng)求函數(shù),可以繞過(guò)middleware。
結(jié)合前面兩種方法的缺憾和上述的測(cè)試框架/工具,下面介紹兩種筆者常用的兩種調(diào)試/測(cè)試方法:
1. 對(duì)于功能模塊,采用單元測(cè)試的方法。單元測(cè)試常見(jiàn)于TDD的研發(fā)流程中,一方面可以驗(yàn)證所寫的程序模塊運(yùn)行后的行為是否符合設(shè)計(jì)的測(cè)試用例,另一方面可以在修改代碼后,快速驗(yàn)證是否改出了問(wèn)題,是否與原有行為保持一致。采用單元測(cè)試的方法,既可以實(shí)現(xiàn)功能模塊的調(diào)試/測(cè)試功能,也能有效的避免重復(fù)性工作,有效的彌補(bǔ)了前面所述的第一種方法的缺點(diǎn)。
python本身自帶了一套u(yù)nittest框架,而diango對(duì)于它又做了一層封裝,可以根據(jù)喜好選擇使用,筆者通常還是習(xí)慣使用python自帶的單元測(cè)試框架。一個(gè)簡(jiǎn)單的單元測(cè)試代碼如下:
import unittest class TestStringMethods(unittest.TestCase): def test_upper(self): self.assertEqual('foo'.upper(), 'FOO') def test_isupper(self): self.assertTrue('FOO'.isupper()) self.assertFalse('Foo'.isupper()) def test_split(self): s = 'hello world' self.assertEqual(s.split(), ['hello', 'world']) # check that s.split fails when the separator is not a string with self.assertRaises(TypeError): s.split(2) if __name__ == '__main__': unittest.main()
2. 對(duì)于整個(gè)請(qǐng)求,采用RequestFactory來(lái)實(shí)現(xiàn)類函數(shù)式調(diào)用的方法,從而可以實(shí)現(xiàn)調(diào)用view的請(qǐng)求函數(shù)。采用這個(gè)方法,可以有效避免前面第二種方法中需要重啟服務(wù)的缺陷,當(dāng)你修改了代碼后,只要重新reload一下模塊,即可實(shí)現(xiàn)新的調(diào)用;同時(shí),你也可以在代碼中拿到對(duì)應(yīng)的response內(nèi)容,做必要的校驗(yàn)處理。
然而,對(duì)于我們使用rest framework 框架來(lái)做REST API開(kāi)發(fā)來(lái)說(shuō),Django原生的RequestFactory還是有一點(diǎn)缺陷,就是不能做authenticate。因?yàn)閞est framework中的authenticate是做在request前面的,而不是在middleware中,所以采用原生的RequestFactory無(wú)法繞過(guò)authenticate。不過(guò),rest framework又重新封裝了一個(gè)APIRequestFactory類,提供了相關(guān)的模擬鑒權(quán)功能,常見(jiàn)的用法如下:
from rest_framework.test import APIRequestFactory from rest_framework.test import force_authenticate # Using the standard RequestFactory API to create a form POST request factory = APIRequestFactory() request = factory.post('/notes/', {'title': 'new idea'}, format='json') # force authenticate user = User.objects.get(username='olivia') force_authenticate(request, user=user) # call the view request view = AccountDetail.as_view() response = view(request)
上面所述的方法,只是筆者目前常用的四種方法,在實(shí)際工作中根據(jù)需要進(jìn)行選擇使用。當(dāng)然,我相信還有更多更好的其他方法。
感謝各位的閱讀!關(guān)于“在Django下如何測(cè)試與調(diào)試REST API”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!