国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

關于前端開發談談單元測試

0x584a / 2547人閱讀

摘要:很快我發現有一個誤區,許多人認為單元測試必須是一個集中運行所有單元的測試,并一目了然。許多人認為單元測試,甚至整個測試都是在編碼結束后的一道工序,而修復也不過是在做垃圾掩埋一類的工作。

單元測試Unit Test

很早就知道單元測試這樣一個概念,但直到幾個月前,我真正開始接觸和使用它。究竟什么是單元測試?我想也許很多使用了很久的人也不一定能描述的十分清楚,所以寫了這篇文章來嘗試描述它的特征和原則,以幫助更多人。

什么是單元測試?

先來看看單元測試的定義,在維基百科英文版中可以找到Kolawa Adam在 Automated Defect Prevention: Best Practices in Software Management 一書中對單元測試的定義:

  

In computer programming, unit testing is a method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures are tested to determine if they are fit for use.

重點在于最后,單元測試的目的顯而易見,用來確定是否適合使用。而測試的方法則包括控制數據,使用和操作過程。那么以我的理解,每個單元測試就是一段用于測試一個模塊或接口是否能達到預期結果的代碼。開發人員需要使用代碼來定義一個可用的衡量標準,并且可以快速檢驗。

很快我發現有一個誤區,許多人認為單元測試必須是一個runner集中運行所有單元的測試,并一目了然。不,這僅僅是一種自動化單元測試的最佳實踐,在一些小型項目中單元測試可能僅僅是一組去除其他特性的接口調用。甚至在一些圖形處理或布局的項目中單元測試可以結合自身特性變的十分有趣,比如Masonry,一個網格布局庫,在它的單元測試中不是一個紅或綠的條目,而是一行一行的小格布局用以說明布局被完成的事實,這樣比代碼檢查布局是否正確再以顏色顯示結果來得更直觀高效,也避免了測試程序本身的bug導致的失誤。

打個比方,單元測試就像一把尺子,當測量的對象是一個曲面時,也許可以花費大力氣去將它抽象成平面,但我更提倡量身定做一把彎曲的尺子去適應這個曲面。無論怎樣,單元測試是為了生產代碼而寫,它應當足夠的自由奔放,去適應各種各樣的生產代碼。

為什么要單元測試?

也許定義中已經很清楚的指明了其意義,確認某段代碼或模塊或接口是否適合使用,但我想會有更多的人認為,直接在測試環境中使用軟件可以更加確保軟件是否可用。不,在實際使用過程中會伴隨著一大批的附帶操作大量增加測試時間,并且無法保證其測試覆蓋率。所以我認為單元測試的目的并不僅僅是確認是否可用,而是更高效更穩定的確認其是否可用。

隨著項目規模的增加,函數、方法、變量都在遞增,尤其是進度的不足,來自產品經理的壓力,還有QA所帶來的各種Bug報告會讓原本整潔的代碼變得一片混亂。我甚至見過同一個接口以不同的名稱出現在8個不同的控制器中。這時也許我們首先想到的是重構,可是等等,在重構結束時我們如何確定項目僅僅是被重構了,而不是被改寫了?此時單元測試將是一根救命稻草,它是一個衡量標準,告訴開發人員這么做是否將改變結果。

不僅僅是這樣。許多人認為單元測試,甚至整個測試都是在編碼結束后的一道工序,而修復bug也不過是在做垃圾掩埋一類的工作。但測試應該伴隨整個編碼或軟件周期進行,還有將在后面提到的TDD這樣有趣的東西,單元測試將超前于編碼。我的意思是,單元測試應該是一個框架、標準,經常被形容被腳手架,像建筑一樣,腳手架的高度至少應該和大樓高度不相上下,甚至一開始就搭好腳手架。

如何做單元測試?

弄清了單元測試的目的和意義,但如何開始?很簡單,首先它是一個檢驗,所以應該只有pass或fail兩種情況。而檢驗的對象應該是某個接口或模塊,所以應該調用它獲得一個結果。檢驗這個結果就是單元測試的基本動作,就拿一個除法函數來做例子:

function division (a, b) {
    return a / b;
}
var result = division(4, 2);
if (result === 2) {
    alert("pass");
} else {
    alert("fail");
}

顯然,將會提示pass通過。但是問題來了,這個測試的用例太單一和普通了,如果使用0做除數呢?是NaN?還是Infinity?或者在實際使用時,產品需要一個0來代替這樣一個不符合數學概念的結果去適應必須為數字類型的某種計算,于是division出現了一個bug。另外當覆蓋率增加,也意味著用例的增加,我們需要把if條件語句提出來做成一個函數多次調用。還有alert方法,如果用例太多,我相信你會點確認點到手軟,也許可以直接顯示在頁面上。

所以我添加了一個關于除數為0的用例,并重構了代碼:

function division (a, b) {
    if (b === 0) {
        return 0;
    } else {
        return a / b;
    }
}
function matcher (name, result, expect) {
    if (result === expect) {
        _print(name + "- pass");
    } else {
        _print(name + "- fail");
    }
    function _print (str) {
        var _bar = document.createElement("p");
        _bar.innerText = str;
        document.body.appendChild(_bar);
    }
}
matcher("normal", division(4, 2), 2);
matcher("zero", division(5, 0), 0);

現在可以使用matcher方法添加許多測試用例,并且還能為該用例命名,在頁面中直接顯示每個用例是否通過。這樣一個基本的單元測試就完成了,當然它的覆蓋率還遠遠不夠,這里僅作為一個例子。另外為了提高效率還應該使用顏色來標記是否通過,可以一目了然。

測試驅動開發

TDD是Test Driven Development 的縮寫,也就是測試驅動開發。

通常傳統軟件工程將測試描述為軟件生命周期的一個環節,并且是在編碼之后。但敏捷開發大師Kent Beck在2003年出版了 Test Driven Development By Example 一書,從而確立了測試驅動開發這個領域。

TDD需要遵循如下規則:

寫一個單元測試去描述程序的一個方面。

運行它應該會失敗,因為程序還缺少這個特性。

為這個程序添加一些盡可能簡單的代碼保證測試通過。

重構這部分代碼,直到代碼沒有重復、代碼責任清晰并且結構簡單。

持續重復這樣做,積累代碼。

另外,衡量是否使用了TDD的一個重要標準是測試對代碼的覆蓋率,覆蓋率在80%以下說明一個團隊沒有充分掌握TDD,當然高覆蓋率也不能說一定使用了TDD,這僅僅是一個參考指標。

在我看來,TDD是一種開發技術,而非測試技術,所以它對于代碼構建的意義遠大于代碼測試。也許最終的代碼和先開發再測試寫的測試代碼基本一致,但它們仍然是有很大不同的。TDD具有很強的目的性,在直接結果的指導下開發生產代碼,然后不斷圍繞這個目標去改進代碼,其優勢是高效和去冗余的。所以其特點應該是由需求得出測試,由測試代碼得出生產代碼。打個比方就像是自行車的兩個輪子,雖然都是在向同一個方向轉動,但是后輪是施力的,帶動車子向前,而前輪是受力的,被向前的車子帶動而轉。

行為驅動開發

所謂的BDD行為驅動開發,即Behaviour Driven Development,是一種新的敏捷開發方法。它更趨向于需求,需要共同利益者的參與,強調用戶故事(User Story)和行為。2009年,在倫敦發表的“敏捷規格,BDD和極限測試交流”[3]中,Dan North對BDD給出了如下定義:

  

BDD是第二代的、由外及內的、基于拉(pull)的、多方利益相關者的(stakeholder)、多種可擴展的、高自動化的敏捷方法。它描述了一個交互循環,可以具有帶有良好定義的輸出(即工作中交付的結果):已測試過的軟件。

另外最主觀的區別就是用詞,‘example’取代了‘test’,‘describe’取代了‘class’,‘behaviour’取代了‘method’等等。這正是其特征之一,自然語言的加入,使得非程序人員也能參與到測試用例的編寫中來,也大大降低了客戶、用戶、項目管理者與開發者之間來回翻譯的成本。

簡單來說,我認為BDD更加注重業務需求而不是技術,雖然看起來BDD確實是比ATDD做的更好,但這是一種誤導,這僅僅是就某種環境下而言的。而且以國內的現狀來看TDD要比BDD更適合,因為它不需要所有人員的理解和加入。

單元測試框架

無論如何,單元測試永遠是少不了的。其實在單元測試中測試代碼和生產代碼應該是等量的,正如Robert C. Martin在其 Clean Code: A Handbook of Agile Software Craftsmanship 一書中所寫:

  

測試必須隨生產代碼的演進而修改,測試越臟就越難修改

于是新的測試很難被加入其中,測試代碼的維護變得異常困難,最終在各種壓力之中只有扔掉測試代碼組。但是沒有了測試代碼,就失去了確保對代碼的改動能如愿以償的能力,各種問題隨之而來。因此,單元測試也需要一種行之有效的實踐來確保其質量和可維護性。

所以正如生產代碼一樣,測試代碼也有框架,下面介紹幾種主流的Javascript的單元測試框架。

Jasmine

有一類框架叫做xUnit,來源于著名的JAVA測試框架JUnit,xUnit則代表了一種模式,并且使用這樣的命名。在Javascript中也有這樣的一個老牌框架JsUnit,他的作者是Edward Hieatt來自Pivotal Labs,但在幾年前JsUnit就已經停止維護了,他們帶來了新的BDD框架Jasmine。

Jasmine不依賴于任何框架,所以適用于所有的Javascript代碼。使用一個全局函數 describe 來描述每個測試,并且可以嵌套。describe函數有2個參數,一個是字符串用于描述,一個是函數用于測試。在該函數中可以使用全局函數 it 來定義Specs,也就是單元測試的主要內容, 使用 expect 函數來測試:

describe("A suite", function () {
    it("is a spec", function () {
        var a = true;
        expect(a).toBe(true);
    });
});

另外如果想去掉某個describe,無須注釋掉整段代碼,只需要在describe前面加上x即可忽略該describe。

Matcher

toBe方法是一個基本的 matcher 用來定義判斷規則,可以看得出來Jasmine的方法是非常語義化的,“expect ‘a’ to be true”,如果想判斷否定條件,則只需要在toBe前調用 not 方法:

expect(a).not().toBe(false);

除了toBe這樣基本的還有許多其他的Matcher,比如 toEqual 。很多初學Jasmine會弄不清和toBe的區別,一個簡單的例子就能明白它們的區別:

expect({}).not().toBe({});
expect({}).toEqual({});

一個新建的Object不是(not to be)另一個新建的Object,但是它們是相等(to equal)的。還有 toMatch 可以使用字符串或者正則表達式來驗證,以及其他一些特殊驗證,比如undefined或者boolean的判斷, toThrow 可以檢查函數所拋出的異常。另外Jasmine還支持自定義Matcher,以NaN的檢查為例,像這樣使用beforeEach方法在每個測試執行前添加一個matcher:

beforeEach(function () {
    this.addMatchers({
        toBeNaN: function (expected) {
            return isNaN(expected);
        }
    });
});

可以想到,其參數expected是傳入的一個期望的字面量,而在expect方法中傳入的參數,可以通過 this.acturl 獲取,是否調用了 not 方法則可以通過 this.isNot 獲取,這是一個boolean值。最后測試輸出的失敗信息應該使用 this.message 來定義,不過它是一個function,然后在其中返回一個信息。所以繼續增進toBeNaN:

beforeEach(function () {
    this.addMatchers({
        toBeNaN: function (expected) {
            var actual = this.actual;
            var not = this.isNot ? " not" : "";
            this.message = function () {
                return "Expected " + actual + not + " to be NaN " + expected;
            };
            return isNaN(expected);
        }
    });
});

這樣一個完整的matcher就創建成了。

另外需要說明的是對應beforeEach是在每個spec之前執行, afterEach 方法則是在每個spec之后執行。這是一種AOP,即面向方面的編程(Aspect Oriented Programming)。比如有時候為了測試一個對象,可能需要多次創建和銷毀它,所以為了避免冗余代碼,使用它們是最佳選擇。

還可以使用 jasmine.any 方法來代表一類數據傳入matcher中,比如

expect(123).toEqual(jasmine.any(Number));
expect(function () {}).toEqual(jasmine.any(Function));
Spy方法

一個Spy能監測任何function的調用和獲取其參數。這里有2個特殊的Matcher, toHaveBeenCalled 可以檢查function是否被調用過,還有 toHaveBeenCalledWith 可以傳入參數檢查是否和這些參數一起被調用過,像這樣使用 spyOn 來注冊一個對象中的方法:

var foo, a = null;
beforeEach(function () {
    var foo = {
        set: function (str) {
            a = str;
        }
    }
    spyOn(foo, "set");
    foo.set(123);
});
it("tracks calls", function () {
    expect(foo.set).toHaveBeenCalled();
    expect(foo.set).toHaveBeenCalled(123);
    expect(foo.set.calls[0].args[0]).toEqual(123);
    expect(foo.set.mostRecentCall.args[0]).toEqual(123);
    expect(a).toBeNull();
});

在測試時該function將帶有一個被調用的數組 calls ,而 args 數組就是調用時傳入的參數,另外特殊屬性 mostRencentCall 則代表最后一次調用,和calls[calls.length]一致。需要特別注意的是,這些調用將不會對變量產生作用,所以 a 仍為null。

如果需要調用產生實際的作用,可以在spyOn方法后調用 andCallThrough 方法。還可以通過調用 andReturn 方法設定一個返回值給function。 andCallFake 則可以傳入一個function作為參數去代替原本的function。

spyOn(foo, "set").andCallThrough();

甚至在沒有function的時候可以使用Jasmine的 createSpycreateSpyObj 創建一個spy:

foo = jasmine.createSpy("foo");
obj = jasmine.createSpyObj("obj", [set, do]);

foo(123);
obj.set(123);
obj.do();

其效果相當于spyOn使用在了已存在的function上。

時間控制

上面的方法都在程序順序執行的前提下執行,但 setTimeout 以及 setInterval 兩個方法會使代碼分離在時間軸上。所以Jasmine提供了 Clock 方法來模擬時間,以獲取setTimeout的不同狀態。

beforeEach(function () {
    jasmine.Clock.useMock();
});
it("set time", function () {
    var str = 0;
    setTimeout(function () {
        str++;
    }, 100);
    expect(str).toEqual(0);
    jasmine.Click.tick(101);
    expect(str).toEqual(1);
    jasmine.Click.tick(200);
    expect(str).toEqual(3);
});

使用Clock的方法 useMock 來開始時間控制,然后在it中使用 tick 方法來推進時間。

異步

Javascript最大的特色之一就是異步,之前介紹的方法如果存在異步調用,大部分測試時可能會不通過。因此,需要等異步回調之后再進行測試。

Jasmine提供了 runswaitsFor 兩個方法來完成這個異步的等待。需要將waitsFor方法夾在多個runs方法中,runs方法中的語句會按順序直接執行,然后進入waitsFor方法,如果waitsFor返回false,則繼續執行waitsFor,直到返回true才執行后面的runs方法。

var cb = false;
var ajax = {
    success: function () {
        cb = true;
    }
};
spyOn(ajax, "success");
it("async callback", function () {
    runs(function () {
        _toAjax(ajax);
    });
    waitsFor(function () {
        return ajax.success.callCount > 0;
    });
    runs(function () {
        expect(cb).toBeTruthy();
    });
});

如此,只要在waitsFor中判斷回調函數是否被調用了即可完成異步測試。上面代碼中我使用一個方法名直接代替了ajax請求方法來縮減不必要的代碼。在第一個runs方法中發出了一個ajax請求,然后在waitsFor中等待其被調用,當第二個runs執行時說明回調函數已經被調用了,進行測試。

Qunit

它是由jQuery團隊開發的一款測試套件,最初依賴于jQuery庫,在2009年時脫離jQuery的依賴,變成了一個真正的測試框架,適用于所有Javascript代碼。

Qunit采用斷言(Assert)來進行測試,相比于Jasmine的matcher更加多的類型,Qunit更集中在測試的度上。 deepEqual 用于比較一些縱向數據,比如Object或者Function等。而最常用的 ok 則直接判斷是否為true。異步方面Qunit也很有趣,通過 stop 來停止測試等待異步返回,然后使用 start 繼續測試,這要比Jasmine的過程化的等待更自由一些,不過有時也許會更難寫一些。Qunit還擁有3組AOP的方法( done 和 "begin" )來對應于整個測試,測試和模塊。

對于Function的跟蹤測試,Qunit似乎完全沒有考慮。不過可以使用另外一個測試框架為Qunit帶來的插件 sinon-qunit。這樣就可以在test中使用 spy 方法了。

Sinon

Sinon并不是一個典型的單元測試框架,更像一個庫,最主要的是對Function的測試,包括 SpyStub 兩個部分,Spy用于偵測Function,而Stub更像是一個Spy的插件或者助手,在Function調用前后做一些特殊的處理,比如修改配置或者回調。它正好極大的彌補了Qunit的不足,所以通常會使用Qunit+Sinon來進行單元測試。

值得一提的是,Sinon的作者Christian Johansen就是 Test-Driven JavaScript Development 一書的作者,這本書針對Javascript很詳細的描述了單元測試的每個環節。

Mocha

它的作者就是在Github上粉絲6K的超級Jser TJ Holowaychuk,可以在他的頁面上看到過去一年的提交量是5700多,擁有300多個項目,無論是誰都難以想象他是如何進行coding的。

理所當然的,Mocha充滿了Geek感,不但可以在bash中進行測試,而且還擁有一整套命令對測試進行操作。甚至使用 diff 可以查看當前測試與上一次成功測試的代碼不一致。

不僅僅是這樣,Mocha非常得自由。Mocha將更多的方法集中在了describe和it中,比如異步的測試就非常棒,在it的回調函數中會獲取一個參數 done ,類型是function,用于異步回調,當執行這個函數時就會繼續測試。還可以使用 onlyskip 去選擇測試時需要的部分。Mocha的接口也一樣自由,除了 BDD 風格和Jasmine類似的接口,還有 TDD 風格的 (suite test setup teardown suiteSetup suiteTeardown),還有AMD風格的 exports,Qunit風格等。同時測試報告也可以任意組織,無論是列表、進度條、還是飛機跑道這樣奇特的樣式都可以在bash中顯示。

前端測試工具

Client/Server 測試

相比于服務端開發,前端開發在測試方面始終面臨著一個嚴峻的問題,那就是瀏覽器兼容性。Paul Irish曾發表文章Browser Market Pollution: IE[x] Is the New IE6闡述了一個奇怪的設想,未來你可能需要在76個瀏覽器上開發,因為每次IE的新版本都是一個特別的瀏覽器,而且還有它對之前所有版本的兼容模式也是一樣。雖然沒人認為微軟會繼續如此愚蠢,不過這也說明了一個問題,前端開發中瀏覽器兼容性是一個永遠的問題,而且我認為即使解決了瀏覽器的兼容性問題,未來在移動開發方面,設備兼容性也是一個問題。

所以在自動化測試方面也是如此,即使所有的單元測試集中在了一個runner中,前端測試仍然要面對至少4個瀏覽器內核以及3個電腦操作系統加2個或更多移動操作系統,何況還有令移動開發人員頭疼的Android的碎片化問題。不過可以安心的是,早已存在這樣的工具可以捕獲不同設備上的不同瀏覽器,并使之隨時更新測試結果,甚至可以在一個終端上看到所有結果。

工具介紹

JSTD(Javascript Test Driver)是一個最早的C/S測試工具,來自Google,基于JAVA編寫,跨平臺,使用命令行控制,還有很好的編輯器支持,最常用于eclipse。不過它無法顯示測試對象的設備及瀏覽器版本,只有瀏覽器名是不夠的。另外JSTD已經慢慢不再活躍,它的早正如它的老。

Google的新貴Karma出現了,它使用Nodejs構建,因此跨平臺,還支持PhantomJS瀏覽器,還支持多種框架,包括以上介紹的Jasmine、Qunit和Mocha。一次可以在多個瀏覽器及設備中進行測試,并控制瀏覽器行為和測試報告。雖然它不支持Nodejs的測試,不過沒什么影響,因為Nodejs并不依賴于瀏覽器。

還有TestSwarm,出自jQuery之父John Resig之手,看來jQuery的強大果然不是偶然的,在測試方面非常到位,各種工具齊全。它最特別的地方在于所有測試環境由服務器提供,包括各種版本的主流瀏覽器以及iOS5的iphone設備,不過目前加入已經受限。

最受矚目的當屬Buster,其作者之一就是Christian Johansen。和Karma很像,也使用Nodejs編寫跨平臺并且支持PhantomJS,一次測試所有客戶端。更重要的是支持Nodejs的測試,同樣支持各種主流測試框架。不過目前還在Beta測試中,很多bug而且不能很好的兼容Windows系統。它的目標還包括整合Browser Stack。

基于網頁的測試

到目前為止我們的測試看起來十分的完美了,但是別忘了,在前端開發中存在交互問題,不能期待QA玩了命的點擊某個按鈕或者刷新一個頁面并輸入一句亂碼之類的東西來測試代碼。即使是開發者本身也會受不了,如果產品本身擁有一堆復雜的表單和邏輯的話。

Selenium是一個測試工具集,由Thoughtworks開發,分為兩部分。Selenium IDE是一個Firefox瀏覽器的插件,可以錄制用戶行為,并快速測試。

而Selenium WebDriver是一個多語言的驅動瀏覽器的工具,支持Python、Java、Ruby、Perl、PHP或.Net。并且可以操作IE、Firefox、Safari和Chrome等主流瀏覽器。通過 open , type , click , waitForxxx 等指令來模擬用戶行為,比如用Java測試:

public void testNew() throws Exception {
    selenium.open("/");
    selenium.type("q", "selenium rc");
    selenium.click("btnG");
    selenium.waitForPageToLoad("30000");
    assertTrue(selenium.isTextPresent("Results * for selenium rc"));
}

首先跳轉到跟目錄,然后選擇類型,點擊按鈕G,并等待頁面載入30秒,然后使用斷言測試。這樣就完成了一次用戶基本行為的模擬,不過復雜的模擬以及在一些非鏈接的操作還需要格外注意,比如Ajax請求或者Pjax的無刷新等等。

另外還有一款可以模擬用戶行為的網頁測試工具WATIR,是Web Application Testing in Ruby的縮寫,顯然它只支持Ruby語言來操作瀏覽器模擬用戶行為。官方聲稱它是一個簡單而靈活的工具,無論怎樣至少就官方網站的設計來看要比Selenium簡約多了。同樣支持模擬鏈接點擊,按鈕點擊,還有表單的填寫等行為。不過WATIR不支持Ajax的測試。和其他Ruby庫一樣需要gem來安裝它:

gem install watir --no-rdoc --no-ri

然后使用它

require "rubygems"
require "watir"
require "watir-webdriver"
browser = Watir::Browser.new
browser.goto "http://www.example.com/form"
browser.test_field(:name => "entry.0.single").set "Watir"
browser.radio(:value => "Watir").set
browser.radio(:value => "Watir").clear
browser.checkbox(:value => "Ruby").set
browser.checkbox(:value => "Javascript").clear
browser.button(:name => "submit").click

這樣就使用watir完成了一次表單填寫。

持續集成測試

持續集成就是通常所謂的CI(Continuous integration),持續不斷的自動化測試新加入代碼后的項目。它并不屬于單元測試,而是另外的范疇,不過通過使用CI服務可以很容易的在Github上測試項目,而這也就是持續集成的意義。

下面以我的jQ小插件Dialog為例介紹一下Travis-CI的使用方法,注冊Travis,然后鏈接自己的Github,選擇要進行持續集成的項目。此時會顯示build failing,那是因為還沒有在項目中進行相關配置。

首先需要使用Grunt等工具配置好測試框架的自動化測試,細節可以參考我之前的文章改進我的Workflow。然后在 package.json 中添加一下代碼來指定執行的腳本:

"scripts": {
    "test": "grunt jasmine:test"
}

接著添加一個文件 .travis.yml 來配置travis:

language: node_js
node_js: 
  - "0.8"
before_script:
  - npm install -g grunt-cli

language 是集成測試所使用的語言,這里前端開發當然是使用Nodejs,在 node_js 中指定版本即可。當然Travis還支持其他多種語言,以及后端數據庫等。

before_script 則是在測試前執行的腳本程序,這里在全局安裝Grunt-cli即可,因為默認的Travis會執行 npm install 將package.json中指定的Node包安裝到項目。

最后在Github中還需要在項目的Setting中的Service Hooks中配置Travis,輸入Token并保存。或者直接在Travis中點擊該項目條目中的扳手圖標進入Github,會自動配置好。

另外,如果在Github上為README文件添加一行

[![Build Status](https://travis-ci.org/tychio/dialog.png?branch=master)](https://travis-ci.org/tychio/dialog)

就可以持續直觀的顯示其測試結果。

博客原文:http://www.tychio.net/tech/2013/07/10/unit-test.html

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/8689.html

相關文章

  • 談談為什么寫單元測試

    摘要:原文作者鍵盤男單元測試是什么單元測試是針對程序的最小單元來進行正確性檢驗的測試工作。因此,首要任務,就是對單元測試全面了解。作為一名經驗豐富的程序員,寫單元測試更多的是對自己的代碼負責。 原文:http://www.jianshu.com/p/bc99678b1d6e作者:鍵盤男kkmike999 showImg(/img/bVCqyN); 單元測試是什么 單元測試 是針對 程序的最小...

    ermaoL 評論0 收藏0
  • 談談項目的重構與測試

    這篇文章摘自我的博客, 歡迎大家沒事去逛逛~ 背景 這幾個月我開發了公司里的一個restful webservice,起初技術選型的時候是采用了flask框架。雖然flask是一個同步的框架,但是可以配合gevent或者其它方式運行在異步的容器中(測試鏈接),效果看上去也還可以,因此就采用了這種方式。 后面閱讀了tornado的源碼,也去了解了各種協程框架以及運行的原理。總感覺flask的這種同步...

    Lavender 評論0 收藏0
  • 談談項目的重構與測試

    這篇文章摘自我的博客, 歡迎大家沒事去逛逛~ 背景 這幾個月我開發了公司里的一個restful webservice,起初技術選型的時候是采用了flask框架。雖然flask是一個同步的框架,但是可以配合gevent或者其它方式運行在異步的容器中(測試鏈接),效果看上去也還可以,因此就采用了這種方式。 后面閱讀了tornado的源碼,也去了解了各種協程框架以及運行的原理。總感覺flask的這種同步...

    wuaiqiu 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<