在使用持續(xù)集成之前,很多開(kāi)發(fā)團(tuán)隊(duì)都是用每日構(gòu)建(nightly build)。當(dāng)時(shí),微軟使用這個(gè)實(shí)踐很多年了。誰(shuí)破壞了構(gòu)建,就要負(fù)責(zé)監(jiān)視后續(xù)的構(gòu)建構(gòu)成,直至發(fā)現(xiàn)下一個(gè)破壞了構(gòu)建的人。
對(duì)于大多數(shù)項(xiàng)目來(lái)說(shuō),采納持續(xù)集成實(shí)踐是向高效率和高質(zhì)量邁進(jìn)的一大步。它保證那些創(chuàng)建大型復(fù)雜系統(tǒng)的團(tuán)隊(duì)具有高度的自信心和控制力。一旦代碼提交引入了問(wèn)題,持續(xù)集成就能為我們提供快速的反饋,從而確保我們作為一個(gè)團(tuán)隊(duì)所開(kāi)發(fā)的軟件是可以工作的。 持續(xù)集成的主要關(guān)注對(duì)象是開(kāi)發(fā)團(tuán)隊(duì)。持續(xù)集成系統(tǒng)的輸出通常作為手工測(cè)試流程和后續(xù)發(fā)布流程的輸入。在軟件的發(fā)布過(guò)程中,很多浪費(fèi)來(lái)自于測(cè)試和運(yùn)維環(huán)節(jié)。 例如:我們常常看到:
采取一種更完整的端到端的方法來(lái)交付軟件。我們通過(guò)一鍵式方式把軟件的某個(gè)版本部署好,甚至可以將其一鍵式部署到生成環(huán)境中,這樣就可以建立了一個(gè)非常有效的反饋環(huán)--由于很容易將應(yīng)用程序部署到測(cè)試環(huán)境中,所以團(tuán)隊(duì)可以同時(shí)得到軟件功能和部署流程兩個(gè)方面的快速反饋。因?yàn)椴渴鹆鞒?無(wú)論是測(cè)試,集成)都是自動(dòng)化的,所以可以頻繁且有規(guī)律的運(yùn)行并被測(cè)試,從而降低發(fā)布風(fēng)險(xiǎn),也降低了向開(kāi)發(fā)團(tuán)隊(duì)傳遞有關(guān)部署流程的知識(shí)時(shí)的風(fēng)險(xiǎn)。
從精益的角度來(lái)看,我們實(shí)現(xiàn)了一個(gè)"拉式系統(tǒng)",測(cè)試團(tuán)隊(duì)只要自己?jiǎn)螕舭粹o,就能輕松部署。管理人員也能容易得到一些關(guān)鍵的度量指標(biāo),比如周期時(shí)間,吞吐量以及代碼質(zhì)量。
什么是構(gòu)建:在現(xiàn)代軟件學(xué)中,可能經(jīng)常聽(tīng)到CMMI,ISO(大型團(tuán)隊(duì))、中小型團(tuán)隊(duì)(敏捷開(kāi)發(fā)、XP編程)
構(gòu)建工具:MSBuild、Maven、Ant、NAnt、Gradle
Unit是整個(gè)金字塔的基石(在建筑行業(yè),基石是做建筑物基礎(chǔ)的石頭),如果基石不穩(wěn),Service和UI何談?dòng)袠?gòu)建意義呢?只有基石穩(wěn)如磐石,上層建筑才夠堅(jiān)固。本來(lái)想拿瑞士做鐘表的例子來(lái)說(shuō)明下,但同事說(shuō)的汽車?yán)痈谩R惠v汽車由許多配件組成,如果有以下兩種選擇,你會(huì)選擇哪個(gè)呢?
1. 所有單元配件沒(méi)有測(cè)試過(guò),在4S店,銷售人員告訴你:剛組裝好,已經(jīng)開(kāi)了一天,能跑起來(lái),你可以試試;2. 所有單元配件在生產(chǎn)過(guò)程已經(jīng)經(jīng)過(guò)嚴(yán)格測(cè)試,在4S點(diǎn),銷售人員告訴你,已經(jīng)通過(guò)國(guó)家認(rèn)證,出廠合格,有質(zhì)量保證,你可以試試;
MSBuild 是 Microsoft 和 Visual Studio的生成系統(tǒng)。它不僅僅是一個(gè)構(gòu)造工具,應(yīng)該稱之為擁有相當(dāng)強(qiáng)大擴(kuò)展能力的自動(dòng)化平臺(tái)。MSBuild平臺(tái)的主要涉及到三部分:執(zhí)行引擎、構(gòu)造工程、任務(wù)。其中最核心的就是執(zhí)行引擎,它包括定義構(gòu)造工程的規(guī)范,解釋構(gòu)造工程,執(zhí)行“構(gòu)造動(dòng)作”;構(gòu)造工程是用來(lái)描述構(gòu)造任務(wù)的,大多數(shù)情況下我們使用MSBuild就是遵循規(guī)范,編寫一個(gè)構(gòu)造工程;MSBuild引擎執(zhí)行的每一個(gè)“構(gòu)造動(dòng)作”就是通過(guò)任務(wù)實(shí)現(xiàn)的,任務(wù)就是MSBuild的擴(kuò)展機(jī)制,通過(guò)編寫新的任務(wù)就能夠不斷擴(kuò)充MSBuild的執(zhí)行能力。所以這三部分分別代表了引擎、腳本和擴(kuò)展能力。MSBuild的簡(jiǎn)單介紹與使用
配置管理:使用版本控制版本控制系統(tǒng)(源代碼控制管理系統(tǒng))是保存文件多個(gè)版本的一種機(jī)制。一般來(lái)說(shuō),包括Subversion、Git在內(nèi)的開(kāi)源工具就可以滿足絕大多數(shù)團(tuán)隊(duì)的需求。所有的版本控制系統(tǒng)都需要解決這樣一個(gè)基礎(chǔ)問(wèn)題: 怎樣讓系統(tǒng)允許用戶共享信息,而不會(huì)讓他們因意外而互相干擾?如果沒(méi)有版本控制工具的協(xié)助,在開(kāi)發(fā)中我們經(jīng)常會(huì)遇到下面的一些問(wèn)題:一、 代碼管理混亂。二、 解決代碼沖突困難。三、 在代碼整合期間引入深層BUG。四、 無(wú)法對(duì)代碼的擁有者進(jìn)行權(quán)限控制。五、 項(xiàng)目不同版本發(fā)布困難。
對(duì)所有內(nèi)容都進(jìn)行版本控制
版本控制不僅僅針對(duì)源代碼,每個(gè)與所開(kāi)發(fā)的軟件相關(guān)的產(chǎn)物都應(yīng)該被置于版本控制下,應(yīng)當(dāng)包括:源代碼、測(cè)試代碼、數(shù)據(jù)庫(kù)腳本、構(gòu)建和部署腳本、文檔、web容器(tomcat的配置)所用的配置文件等。
保證頻繁提交可靠代碼到主干
頻繁提交可靠、有質(zhì)量保證的代碼(編譯通過(guò)是最基本要求),能夠輕松回滾到最近可靠的版本,代碼提交之后能夠觸發(fā)持續(xù)集成構(gòu)建,及時(shí)得到反饋。
提交有意義的注釋
強(qiáng)制要求團(tuán)隊(duì)成員使用有意義注釋,甚至可以關(guān)聯(lián)相關(guān)開(kāi)發(fā)任務(wù)的原因是。當(dāng)構(gòu)建失敗后,你知道是誰(shuí)破壞了構(gòu)建,找到可能的原因及定位缺陷位置。這些附加信息,可以縮短我們修復(fù)缺陷的時(shí)間。示例:團(tuán)隊(duì)使用了svn和redmine。
有可以加強(qiáng)的部分
- Git要求每次提交都必須寫提交說(shuō)明,可以借鑒
- 測(cè)試代碼、數(shù)據(jù)庫(kù)腳本單獨(dú)分支
- 構(gòu)建腳本化
這個(gè)流程的起點(diǎn)是開(kāi)發(fā)人員向版本控制庫(kù)提交代碼。此時(shí),持續(xù)集成系統(tǒng)對(duì)這次提交做出響應(yīng),觸發(fā)該流水線的一個(gè)實(shí)例。第一個(gè)階段會(huì)編譯代碼,運(yùn)行單元測(cè)試,執(zhí)行代碼分析,創(chuàng)建軟件二進(jìn)制包。如果所有的單元測(cè)試都通過(guò)了,并且代碼符合編碼標(biāo)準(zhǔn),就將可執(zhí)行代碼打包成可執(zhí)行文件,并放到一個(gè)制品庫(kù)里中。有些在提交而極端,還會(huì)執(zhí)行另外一些任務(wù),比如為驗(yàn)收測(cè)試準(zhǔn)備數(shù)據(jù)庫(kù)。第二個(gè)階段由運(yùn)行時(shí)間較長(zhǎng)的自動(dòng)化驗(yàn)收測(cè)試組成。所以持續(xù)集成服務(wù)器最好支持將測(cè)試分成多組的做法,以便在構(gòu)建網(wǎng)絡(luò)中并行執(zhí)行任務(wù),提高執(zhí)行效率。這個(gè)階段在第一個(gè)階段完成后自動(dòng)觸發(fā)的。部署流水線可能有分支出現(xiàn),這樣就可以將該構(gòu)建版本獨(dú)立部署到多個(gè)不同的環(huán)境中,比如部署到用戶驗(yàn)收環(huán)境、容量測(cè)試環(huán)境和生成環(huán)境。這時(shí),部署到相應(yīng)的環(huán)境,就需要用到自動(dòng)化部署腳本來(lái)執(zhí)行這種部署過(guò)程。測(cè)試人員應(yīng)當(dāng)能看到需要測(cè)試的所有構(gòu)建版本,以及他們的狀態(tài)。目的:最快的得到反饋
3.2部署流水線的相關(guān)實(shí)踐
- 只生成一次二進(jìn)制包我們將所有可執(zhí)行代碼的集合稱作二進(jìn)制包,例如.NET程序集。有時(shí)候代碼不需要編譯,那么這種情況下,二進(jìn)制是所有文件的集合。一種相關(guān)的反模式就是一直使用源代碼而不是二進(jìn)制包。因此,每次講一個(gè)修改部署時(shí),需要自己親自從發(fā)布分支遷出源代碼并重新編譯二進(jìn)制包。同時(shí),還可能因編譯器和某個(gè)依賴的不同版本產(chǎn)生差異。
部署的可視化
測(cè)試分類:
BDD,TDD,ATDDBDD主要是基于場(chǎng)景、面向需求的,ATDD面向驗(yàn)收的,這里不做過(guò)多介紹了。這里主要介紹TDD的一些開(kāi)發(fā)
測(cè)試驅(qū)動(dòng)開(kāi)發(fā)
TDD的優(yōu)點(diǎn)TDD從一開(kāi)就保證了代碼的質(zhì)量:鼓勵(lì)開(kāi)發(fā)人員只開(kāi)發(fā)”最小化“的代碼完成特定測(cè)試功能。遵循SOLID原則: SOLID (單一功能、開(kāi)閉原則、里氏替換、接口隔離以及依賴反轉(zhuǎn))TDD確保了代碼與業(yè)務(wù)需求之間的高度一致性。TDD鼓勵(lì)創(chuàng)建更簡(jiǎn)單,針對(duì)性更強(qiáng)的APITDD鼓勵(lì)更多的溝通,與企業(yè),與團(tuán)隊(duì)內(nèi)部。TDD有助于清除冗余代碼TDD提供了內(nèi)置的回歸測(cè)試。
如果沒(méi)有單元測(cè)試來(lái)幫助查找和診斷缺陷時(shí),大多數(shù)開(kāi)發(fā)人員會(huì)使用調(diào)試器,在他們認(rèn)為出現(xiàn)缺陷的地方設(shè)置斷點(diǎn),有時(shí)將這種方法稱為"散彈槍方法"。
單元測(cè)試的特征:
- 與其他代碼隔離
- 有針對(duì)性
- 與其他開(kāi)發(fā)人員隔離
- 可重復(fù)
- 可預(yù)測(cè)
提交代碼、運(yùn)行測(cè)試的重點(diǎn)是什么?快速捕獲那些因修改向系統(tǒng)中引入的最常見(jiàn)錯(cuò)誤,并通知開(kāi)發(fā)人員,以便他們能快速修復(fù)他們。提交階段提供反饋的價(jià)值在于,對(duì)它的投入可以讓系統(tǒng)高效且更快地工作。
常規(guī)一個(gè)加密、解密方法的測(cè)試
[Test] [Ignore("這個(gè)測(cè)試有問(wèn)題!")] public void TestEncrypt() { FileEncrypt fileEncrypt = new FileEncrypt(); String ii = fileEncrypt.EncryptContext("Hello World", "123"); ii = fileEncrypt.DecryptContext(ii, "123"); Assert.Pass(ii); }
Ignore標(biāo)志的方法,當(dāng)我們運(yùn)行測(cè)試實(shí)例時(shí),可以忽略Category
可以只運(yùn)行指定目錄的測(cè)試用例Rhino.Mocks的簡(jiǎn)單實(shí)用
[Test] [Category("模擬對(duì)象")] public void TestCustomer() { MockRepository mocks = new MockRepository(); ICustomer customer = mocks.StrictMock<ICustomer>(); customer.Expect(c => c.ShowTitle("")).Return("567"); Expect.Call(customer.Pid).Return(30); customer.Replay(); Assert.AreEqual(customer.ShowTitle(""), "567"); } [Test] public void SayHelloWorld() { MockRepository mocks = new MockRepository(); INameSource nameSource = mocks.DynamicMock<INameSource>(); Expect.Call(nameSource.CreateName(null, null)) .IgnoreArguments() .Do(new NameSourceDelegate(Formal)); mocks.ReplayAll(); const string expected = "Hi, my name is Ayende Rahien"; string actual = new Speaker("Bright", "Gong", nameSource).Introduce(); Assert.AreEqual(expected, actual); } delegate string NameSourceDelegate(string first, string surname); public class Speaker { PRivate readonly string _firstName; private readonly string _surname; private readonly INameSource _nameSource; public Speaker(string firstName, string surname, INameSource nameSource) { this._firstName = firstName; this._surname = surname; this._nameSource = nameSource; } public string Introduce() { string name = _nameSource.CreateName(_firstName, _surname); return string.Format("Hi, my name is {0}", name)
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注