Ruby單元測(cè)試框架實(shí)例分析.剛開(kāi)始寫(xiě)一個(gè)單元測(cè)試框架的時(shí)候代碼是很少的,但當(dāng)我想給它加入一些特性時(shí)就變得沒(méi)有那么精煉了:) 幸運(yùn)的是重寫(xiě)是很容易的。我們真正需要做的是執(zhí)行下面的代碼:
創(chuàng)新互聯(lián)-專(zhuān)業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比平谷網(wǎng)站開(kāi)發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫(kù),直接使用。一站式平谷網(wǎng)站制作公司更省心,省錢(qián),快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋平谷地區(qū)。費(fèi)用合理售后完善,十多年實(shí)體公司更值得信賴。describe "some test" do it "should be true" do true.should == true end it "should show that an expression can be true" do (5 == 5).should == true end it "should be failing deliberately" do 5.should == 6 endend
正如你看到的,它很像是一個(gè)基本的Rspec測(cè)試。讓我們寫(xiě)一些代碼來(lái)執(zhí)行它。
譯注:RSpec 工具是一個(gè) Ruby 軟件包,可以用它構(gòu)建有關(guān)您的軟件的規(guī)范。該規(guī)范實(shí)際上是一個(gè)描述系統(tǒng)行為的測(cè)試。
構(gòu)建一個(gè)簡(jiǎn)單的框架
首先要做的是使用“describe”來(lái)定義一個(gè)新的測(cè)試。既然我們想要把”describe” block放在任何地方(例如,文件本身),我們需要對(duì)Ruby做一點(diǎn)擴(kuò)展?!皃uts”函數(shù)在Kernel block中,因此可以在任何地方使用(因?yàn)镺bject類(lèi)包含了Kernel并且Ruby中的每個(gè)對(duì)象都繼承自O(shè)bject類(lèi)),同樣的我們會(huì)把describe放到Kernel block中以賦予同樣的能力):
module Kernel def describe(description, &block) tests = Dsl.new.parse(description, block) tests.execute endend
譯注:Ruby block:Ruby語(yǔ)言的block功能類(lèi)似回調(diào)函數(shù)。
正如codego.net上面寫(xiě)的的,”describe”接收一個(gè)用來(lái)描述測(cè)試的字符串和包含了測(cè)試代碼的block。在這里,我們將測(cè)試的代碼和”describe”分開(kāi)講解(例如,”it” block)。因此我們創(chuàng)建了Dsl類(lèi),用它的parse函數(shù)處理待測(cè)試的block,結(jié)果會(huì)產(chǎn)生一個(gè)可以執(zhí)行我們所有測(cè)試的對(duì)象,但是不要高興得太早。Dsl類(lèi)看上去是這樣的:
class Dsl def initialize @tests = {} end def parse(description, block) self.instance_eval(&block) Executor.new(description, @tests) end def it(description, &block) @tests[description] = block endend
這里要做的是在Dsl對(duì)象的上下文里對(duì)block求值:
?1 self.instance_eval(&block)
我們的Dsl對(duì)象有一個(gè)”it”函數(shù),同樣也接收一個(gè)描述和一個(gè)block,這里和describe block包含的內(nèi)容完全一致,一切都運(yùn)行得很好(例如,我們基本上會(huì)在幾個(gè)函數(shù)調(diào)用時(shí)使用”it”函數(shù),每次都傳入一個(gè)描述和一個(gè)block)。我們還可以在Dsl對(duì)象中定義其他的函數(shù),并且這些函數(shù)會(huì)成為允許在”describe” block中使用的“語(yǔ)言”的一部分)。
在describe block中,”it”函數(shù)會(huì)為每個(gè)”it” block調(diào)用一次。每次調(diào)用時(shí),會(huì)把輸入的block以測(cè)試描述作為鍵值存儲(chǔ)在哈希表中。完成這些以后,我們只要?jiǎng)?chuàng)建一個(gè)Executor對(duì)象,可以對(duì)我們所有的測(cè)試block進(jìn)行迭代,調(diào)用它們并產(chǎn)生執(zhí)行結(jié)果。Executor代碼如下:
class Executor def initialize(description, tests) @description = description @tests = tests @success_count = 0 @failure_count = 0 end def execute puts "#{@description}" @tests.each_pair do |name, block| print " - #{name}" result = self.instance_eval(&block) result ? @success_count += 1 : @failure_count += 1 puts result ? " SUCCESS" : " FAILURE" end summary end def summary puts "\n#{@tests.keys.size} tests, #{@success_count} success, #{@failure_count} failure" endend
我們的executor代碼非常簡(jiǎn)單。輸出”describe” block的描述,然后遍歷所有存儲(chǔ)的”it” block并且在executor對(duì)象中執(zhí)行它們。這么處理沒(méi)有什么特別原因,但這意味著executor對(duì)象同樣也可以包含其他函數(shù),并且可以在”it” block中作為一種“語(yǔ)言”來(lái)使用(比如,我們dsl的一部分可以定義為executor的一個(gè)函數(shù))。譬如,我們可以在executor上定義下列函數(shù):
def should_be_five(x) 5 == x end
這個(gè)函數(shù)同樣可以在”it” block內(nèi)部使用,但對(duì)于我們這個(gè)簡(jiǎn)單的測(cè)試沒(méi)有這個(gè)必要。
所以,”it” block會(huì)計(jì)算并存儲(chǔ)結(jié)果,通常結(jié)果只是”it” block最后一個(gè)語(yǔ)句的返回值(按照常規(guī)的Ruby)。這里,我們希望確保最后一個(gè)語(yǔ)句總是返回一個(gè)布爾值(標(biāo)明測(cè)試通過(guò)或失?。?,通過(guò)它我們可以輸出一些有意義提示。
我們還差最后一步,”should”函數(shù)代碼如下:
true.should == true5.should == 5
每個(gè)對(duì)象都應(yīng)當(dāng)提供自己”should”函數(shù),代碼如下:
class Object def should self endend
這個(gè)函數(shù)并沒(méi)有真正做什么工作(僅僅是返回對(duì)象本身);它僅僅是一個(gè)讓測(cè)試讀起來(lái)更好的語(yǔ)法。
在這個(gè)階段,我們只是將測(cè)試計(jì)算的結(jié)構(gòu)轉(zhuǎn)換成一個(gè)字符串,表明測(cè)試結(jié)果通過(guò)或失敗并輸出。在這個(gè)過(guò)程中,我們會(huì)統(tǒng)計(jì)通過(guò)或失敗的測(cè)試數(shù)量,所以可以在最后給出一個(gè)總結(jié)報(bào)告。這就是我們所需要的所有的代碼,如果我們將他們放到一起,就是下面的44行代碼:
module Kernel def describe(description, &block) tests = Dsl.new.parse(description, block) tests.execute endendclass Object def should self endendclass Dsl def initialize @tests = {} end def parse(description, block) self.instance_eval(&block) Executor.new(description, @tests) end def it(description, &block) @tests[description] = block endendclass Executor def initialize(description, tests) @description = description @tests = tests @success_count = 0 @failure_count = 0 end def execute puts "#{@description}" @tests.each_pair do |name, block| print " - #{name}" result = self.instance_eval(&block) result ? @success_count += 1 : @failure_count += 1 puts result ? " SUCCESS" : " FAILURE" end summary end def summary puts "\n#{@tests.keys.size} tests, #{@success_count} success, #{@failure_count} failure" endend
如果我們“需要”使用這個(gè)框架執(zhí)行最初的那個(gè)測(cè)試,我們會(huì)得到下面輸出結(jié)果:
some test
- should be true SUCCESS
- should show that an expression can be true SUCCESS
- should be failing deliberately FAILURE
3 tests, 2 success, 1 failure
太好了!現(xiàn)在,如果你因沒(méi)有一個(gè)單元測(cè)試框架而煩惱并且不想莽撞地寫(xiě)代碼,只要花上5分鐘你就可以得到一個(gè)能夠助你一臂之力的測(cè)試框架。當(dāng)然,這里有一些略微夸大;你很快就會(huì)想到這里缺少額外的驗(yàn)證API、更好的輸出、對(duì)象仿真和測(cè)試樁等等。然而,我們可以很容易的在精簡(jiǎn)的框架上擴(kuò)展其中的一些功能(例如,增加額外的DSL元素)——只消花費(fèi)很小的努力。如果你不相信我,可以看看bacon ,它只用了幾百行代碼就完成了Rspec一個(gè)精簡(jiǎn)版。我編寫(xiě)的Attest測(cè)試框架是另一個(gè)很好的例子(這么說(shuō)有自賣(mài)自夸的嫌疑:P)。這兩者都缺少任何內(nèi)建的test double 支持,我會(huì)在另外一個(gè)時(shí)間討論如何添加test double支持。
譯注:Test Double:在對(duì)象編程中“自動(dòng)化單元測(cè)試”的專(zhuān)業(yè)術(shù)語(yǔ),涵蓋的類(lèi)型有Test Stub(測(cè)試樁)、Mock Object、Test Spy、Fake Object和Dummy Object。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。
文章題目:Ruby單元測(cè)試框架實(shí)例分析-創(chuàng)新互聯(lián)
鏈接地址:http://jinyejixie.com/article44/pishe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開(kāi)發(fā)、App設(shè)計(jì)、網(wǎng)站營(yíng)銷(xiāo)、建站公司、企業(yè)網(wǎng)站制作、響應(yīng)式網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容