咨詢郵箱 咨詢郵箱:service@yitianxinda.com 咨詢熱(rè)線 咨詢熱(rè)線:18101296137 微(wēi)博 微(wēi)信
北(běi)京軟件(jiàn)開(kāi)發公司全棧測試:平衡單元測試和₹®≈(hé)端到(dào)端測試_北(běi σε )京軟件(jiàn)開(kāi)發公司
發表日(rì)期:2016-06-15  ≤​≈09:36:04    文(wén)章(zhāng)編輯:yi★δ​tianxinda    浏覽次數(shù):

  北(běi)京軟件(jiàn)開(kāiα&∑)發公司全棧測試:平衡單元測試和(hé)端到(dào)端測試全™ε↓棧開(kāi)發人(rén)員(yuán)的(de)特點是(ε÷shì)能(néng)夠從(cóng)頭到(dà™ εo)尾交付并發布一(yī)個(gè)特性。教程和(hé)書(shū)籍常常 ☆♣側重于搭建全棧開(kāi)發環境和(hé)讓測¥♠ε試能(néng)夠進行(xíng)所需要( Ωyào)的(de)“管件(jià€γ↑₽n)(plumbing)”(我綜合運用(yò&​<γng)了(le)Angular、Rails、Boo>₽♠tstrap和(hé)Postgres)。但(dàn)對(duì)于如≠↔∞(rú)何貫穿整個(gè)Web開(kāi)發棧進行"£σ&(xíng)應用(yòng)程序測試,卻常常缺少(shǎo)指導↕←$。讓我們深入研究下(xià)這(zhè)篇文(wén)≠✘δ≠章(zhāng)。我們将學習(xí)如(rú)何充分(fēn)利用(y¶×♠òng)端到(dào)端測試,包括對(duì)測試什(shén)麽以及如(★®rú)何保證那(nà)些(xiē)測試的(de)可(σ‌≈kě)靠性和(hé)可(kě)維護性進行(xíng)指導。我們還(h∞↓ái)将談及單元測試以及它們在端到(dào)端測試策略中的(d​∏₽"e)作(zuò)用(yòng)。但(dàn)首先,我們要(yào)±±☆理(lǐ)解編寫測試的(de)根本目的(de)。

  從(cóng)根本上(shàng)講,測試是(shì)為 ‌ε(wèi)了(le)确保應用(yòng)程序®₩✔的(de)行(xíng)為(wèi)符合開(kāi)發者的(de)意願。β↕©它們是(shì)自(zì)動化(huà)的(de)腳本,執行®←•(xíng)代碼并檢查其行(xíng)為(w€'  èi)是(shì)否符合預期。測試編寫得(de)越好(hǎo),就(jiù)λ£越可(kě)以依賴它們為(wèi)部署把關。如(rú)果測♥‍ε&試不(bù)充分(fēn),就(jiù)需要(yào)一(yī)β∏↕×個(gè)QA團隊或者發布有(yǒu)缺陷的(deσπ✔γ)軟件(jiàn)(兩者均意味著(zhe)用(yòng)戶獲得(de)價值的(•€de)速度比理(lǐ)想情況慢(màn)許多(duō))。如(rú)果測αα ™試充分(fēn),就(jiù)可(kě)以 ₩€自(zì)信而快(kuài)速地(dì)'≠±發布,不(bù)需要(yào)批準或者像QA那(nà)樣緩慢(màn)的(d★₩e)人(rén)工(gōng)過程。

  對(duì)于編寫的(de)測試,還↔∏↓(hái)必須權衡未來(lái)的(de)可(k$ ™ě)維護性。應用(yòng)程序會(huì)變,因此測試也(yě™♠)會(huì)變。在理(lǐ)想情況下(xià)"σ≈,測試的(de)修改與軟件(jiàn)的(de)修改是(shì)成正比的(d₩‍e)。如(rú)果你(nǐ)修改了(le)一‍δ(yī)條錯(cuò)誤信息,那(nà)麽你(nǐ)σ★ 不(bù)會(huì)希望大(dà)量重寫測試套件(jiàn)。但(dσ >™àn)是(shì),如(rú)果你(nǐ)徹底地(dì)修改↕​♦‍了(le)一(yī)個(gè)用(yòng)戶流程,那(nà)麽可‍§ φ(kě)以預料,将有(yǒu)大(dà)量的(de)測試需要(yào)重₩≠寫。

  實際上(shàng),這(zhè)意味著(zhe)你(nǐ)∞¥無法将所有(yǒu)測試都(dōu)作(zuò)為(w'✔₹èi)端到(dào)端的(de)全面集成測試,但₹•™(dàn)是(shì)你(nǐ)也(yě)不(bù)能(néng)隻進行(xí☆‍→ng)少(shǎo)得(de)可(kě)憐的(d₩♦±£e)單元測試。這(zhè)就(jiù)關乎如(rú)何達成那(nà)種平衡。

  測試的(de)類型

  測試的(de)種類很(hěn)多(du♥↑φō),但(dàn)對(duì)于本文(wén)而言, <≠ε我們就(jiù)談論兩類:端到(dào)端測試←₩→和(hé)單元測試。

  端到(dào)端測試模拟用(yòng)戶行(x®< íng)為(wèi)。在Web應用(yòng)程序♦ε​¥中,他(tā)們會(huì)啓動服務器(qì),®♦打開(kāi)浏覽器(qì),到(dào)處點擊,斷言♦​₩∏浏覽器(qì)中發生(shēng)了(le)特定的(de)事(÷☆shì)情,讓我們相(xiàng)信功能(néng)可(kě)以正常運行(xí§®ng)。這(zhè)些(xiē)測試會(huì)≠λ☆給我們巨大(dà)的(de)信心,但(dàn)✘∏φ$是(shì)它們緩慢(màn)而脆弱,并且">£同用(yòng)戶界面緊密地(dì)耦合在了(le)一(yī)起。

  單元測試根據代碼單元的(de)公共API運行(xíng)它們。這(λε≈zhè)些(xiē)測試需要(yào)創建一(yī)個(gè)類 ≠的(de)實例,使用(yòng)特定的(de)輸入調用(yòng)↑©‌它的(de)方法,斷言被調用(yòng)的(de✘≥↑Ω)方法達到(dào)了(le)預期的(de)效果(通(t♠™ōng)常是(shì)返回了(le)預期的(de)輸出)。這¶♠(zhè)些(xiē)測試快(kuài)速而穩定,并≤<©♣且不(bù)會(huì)同系統的(de)其他(£€γ&tā)部分(fēn)緊密地(dì)耦合在一(yī)起。×≈÷不(bù)過,它們無法讓你(nǐ)相(xiàng≥'‌)信整個(gè)系統可(kě)以正常運行(xíng)—&m₽≈≥dash;隻是(shì)測試過的(de)代碼單元可(kě)↔​ 以正常運行(xíng)。

  構建一(yī)項特性的(de)任務就(ji∞¶£∞ù)是(shì)要(yào)在兩類測試之間(≥₩jiān)找到(dào)恰當的(de)平衡點。如(rú)果端到→≈✔Ω(dào)端測試太多(duō),那(nà)麽未來(lái​λ→)修改應用(yòng)程序就(jiù)會(huì)痛苦而緩慢(màn)。如•&(rú)果太少(shǎo),那(nà)麽一(yī)些(xiē)不±↔​(bù)易覺察的(de)缺陷就(jiù)會(huì)進入到(dào)≤∞生(shēng)産環境,即使快(kuài)速測✘¥©α試套件(jiàn)的(de)代碼覆蓋率為(wèi)10≥★ 0%。

  從(cóng)用(yòng)戶體(tǐ)驗入手

  你(nǐ)的(de)軟件(jiàn)是(shì)向某個(gè)用(yòng↑&<)戶提供服務,因此,那(nà)個(gè)φ$✔用(yòng)戶應該推動你(nǐ)的(de)工(gōnδ♠g)作(zuò)。我不(bù)建議(yì)使用(yòng)測試來(‍↕≈lái)設計(jì)用(yòng)戶體(tǐ)驗,$ 因此,要(yào)在編寫測試之前弄清楚用(yòng)戶将如(rú)何使用(yò∞∑ng)軟件(jiàn)(要(yào)麽通(tōng)過試€®驗性代碼,要(yào)麽同一(yī)名設計(jì)師(shī)一(yī)起工(σ←gōng)作(zuò))。一(yī)旦弄清楚了(le),就(jiù)可 ↕(kě)以開(kāi)始工(gōng)作(β✔zuò)了(le)。

  在理(lǐ)想情況下(xià),你(nǐ)将為(wèi)¥δ用(yòng)戶體(tǐ)驗的(de)某個(gè)部分(fēn)創​ β±建端到(dào)端的(de)測試,并編寫代碼讓其通(tōng)過測試÷↔★÷。在編寫那(nà)些(xiē)代碼的(de)時(shí)↑♦候,你(nǐ)會(huì)創建單元測試,具體(tǐ)化(huà)需要(✔☆¥yào)創建或修改(通(tōng)常是(shì)後者)的(de)代碼的(de<&±)規範。

  問(wèn)題是(shì),編寫沒有(yǒu)用₹±✘(yòng)戶界面工(gōng)件(jiàn)γ​'★(HTML)可(kě)供參考的(de)、端到(dà©☆$₹o)端的(de)失敗測試很(hěn)難。這(zhè)→©是(shì)因為(wèi),大(dà)部分"™€₽(fēn)端到(dào)端測試的(de)形式都(dōu)≥  ‍是(shì):

  找到(dào)頁面上(shàng)的(de)某個(' gè)元素;

  通(tōng)過某種方式同它交互;

  證實交互成功;

  重複上(shàng)述過程直到(dào)測試結☆Ω§束。

  這(zhè)意味著(zhe),圍繞要(yào)發生(shēng)交互←>↕的(de)用(yòng)戶界面元素(DOM對(duì)象),你(nǐ)'​∏€需要(yào)有(yǒu)一(yī)些(xiē)規範ε₩♣。當把以JavaScript為(wèi)基礎的(de)交互設計(jì↕♥←α)考慮在內(nèi)時(shí),如(rú)果不(bù)實際地(dì§€)構建界面,至少(shǎo)是(shì)部分(fēn)地(dì)構建,就(jσβiù)更難測試了(le)。

  為(wèi)此,要(yào)讓一(yī)個$∏♦•(gè)粗略的(de)UI輪廓在浏覽器(qì)中運行(xí₽÷¶ng)起來(lái)。使用(yòng)預先準γ☆×備好(hǎo)的(de)數(shù)據,并且不(bù)需要($↓yào)考慮備選流程—&mda¶₩sh;一(yī)次專注于一(yī)件(jià¥★£Ωn)事(shì)。它運行(xíng)起來(lái)以後,就(jiù)可(∞→kě)以編寫測試了(le)。

  在這(zhè)樣做(zuò)的(de)時(shí ₽)候,有(yǒu)兩點需要(yào)考慮:這(zhè)個(gè)特性需$‍要(yào)測試嗎(ma)?如(rú)果需要(yào),該如∑"≈(rú)何測試?

  測試什(shén)麽

  雖然在編程上(shàng)沒有(yǒu)愉快(kuà≈"✔<i)路(lù)徑,但(dàn)用(yòng)戶經曆的(de)代碼路(lù×‍σ∏)徑要(yào)比代碼的(de)可(kě)能(↓★∏néng)路(lù)徑少(shǎo)許多→ $(duō)。例如(rú),當用(yòng)戶購(gòu)買一(yī)款産₽ε✔品,根據用(yòng)戶地(dì)址、選擇的(de)發貨方式或者∑↓Ω↕以前的(de)購(gòu)買曆史,我們可(kě)能(nén<δ≠g)會(huì)用(yòng)不(bù)同的(de)方式處理(lǐ)≠€訂單。在所有(yǒu)情況下(xià),用(yòng)戶的(de)體♣↑(tǐ)驗都(dōu)是(shì)一(yī)✔≥♦>樣的(de),這(zhè)樣,在用(yòng)戶看(kàn)來(lái),流↕™♥程隻有(yǒu)一(yī)個(gè)。

  這(zhè)時(shí),你(nǐ)的(de)目标是(shì¶•)測試所有(yǒu)的(de)用(yòng)戶流程。你(nǐ)需要(yào)↑♥★↔一(yī)個(gè)測試套件(jiàn),模§®‍拟一(yī)個(gè)用(yòng)戶做(zuò)你(nǐΩ∑)想要(yào)并希望他(tā)做(zuò)的(de)事(shì)ε→¶,并斷言你(nǐ)想要(yào)提供給該用(yòng)戶的(de)所有∏←♠(yǒu)體(tǐ)驗都(dōu)工(gō‌>πφng)作(zuò)正常。

  假如(rú)你(nǐ)已經知(zhī)道(dào)要(yào)測試什(sh₩✔én)麽,那(nà)應該如(rú)何進行(xíng)呢(nγ≠← e)?

  如(rú)何進行(xíng)端到(dào)端測試

  如(rú)果修改了(le)一(yī)個(gè)流程,那(nà)麽就÷σ∑(jiù)要(yào)修改那(nà)個(gè)流程✔≈♦的(de)測試。由于端到(dào)端測試模拟用(yòn‌<>g)戶活動,所以不(bù)需要(yào)為(wèi)想要(yào)斷言的φ∏¥​(de)每件(jiàn)事(shì)情都(dōu)編寫一(yī)個σ÷α(gè)測試。如(rú)果用(yòng)戶應該>§∞在結算(suàn)界面上(shàng)看(kàn)到(dàoαφ)三段重要(yào)的(de)信息,就(jiù)不(bù)需♦γγ要(yào)編寫三個(gè)測試—&mdas™♣★✘h;一(yī)個(gè)測試檢查所有(yǒu)三段信息就(ji♠★→ù)足夠了(le)。因此,當修改一(yī)個(gè)現(xiàn)有(>→®yǒu)的(de)用(yòng)戶體(tǐ)驗時(shí),要(yào)找一£✔©(yī)個(gè)現(xiàn)有(yǒu)的(de)、可(kě)以改¥×φ÷進的(de)測試。

  否則,就(jiù)需要(yào)一(yī) ✔®個(gè)新的(de)測試。記住,你(nǐ)的(de)目标是(shì)模‌≤∑★拟用(yòng)戶要(yào)做(zuò)的(de)事(shìγ↔)情。務必要(yào)對(duì)如(rú)π✘&何組織測試中的(de)導航和(hé)行(x←♣↑✔íng)為(wèi)開(kāi)誠布公。用(yòng)戶真地(d§λ≤ì)會(huì)直接導航到(dào)某些(♥​₩xiē)深層鏈接嗎(ma)?或者他(tā)們會(huì)點擊某個(↓π®$gè)公用(yòng)的(de)開(kāi)始頁面從(cóngγε)而到(dào)達他(tā)們需要(yào)到(dào)達的(de)®↕φ地(dì)方嗎(ma)?

  這(zhè)很(hěn)難做(zuò),尤其是(shì)通(tōng)常要≈÷☆(yào)使用(yòng)較少(shǎo)的(de  )标記實現(xiàn)該功能(néng)。測試需要γ"(yào)定位特定的(de)DOM元素同其交互,而準确找到(dào)你(§≠nǐ)想要(yào)同其交互的(de)元素并不(bε§'ù)總是(shì)很(hěn)簡單(或者可(kě)能(néng))。你(n™​ Ωǐ)需要(yào)“标識(sig≥÷npost)”。

  标識是(shì)專門(mén)插入DOM中用(yòng)于定位感興趣的♣≠(de)元素的(de)。要(yào)盡早确定這(zhè)些(xiē)标識₽≤₽如(rú)何發揮作(zuò)用(yòng)。不(bù)應該使用(¶Ω‍✘yòng)原本用(yòng)于樣式化(huà)的(de)CSS類✔Ω 來(lái)定位DOM元素。這(zhè)樣✔∑β做(zuò)意味著(zhe)前端開(kāi)發人(r<₹®én)員(yuán)改變類名就(jiù)會(huì)破壞測試。也(yě)不(↕λ•γbù)應該使用(yòng)被JavaScript↔λ> 代碼使用(yòng)的(de)CSS類或數(shù)據屬性(比如(r"→‍ú)前綴為(wèi)js-的(de)類)。這(zhè)會(huì)帶來(lái ≥₩)同樣的(de)破壞。

  使用(yòng)前綴為(wèi)test-的₹ ₹δ(de)CSS類或者前綴為(wèi)data-test-的₹™‌↕(de)屬性是(shì)兩種常用(yòng'©§)的(de)技(jì)術(shù):

  這(zhè)可(kě)能(néng)看(kàn)上(shàng)去(qù"•)讓人(rén)不(bù)舒服……也(yě)₩≈®"确實是(shì)。但(dàn)是(shì),與将測試耦合到(dào§∏≤")內(nèi)容或者展示類相(xiàng)比,這(zhè)λ≈σ☆就(jiù)不(bù)那(nà)麽令人(rén)↓®×ε討(tǎo)厭(yàn)了(le)。這(zhè)裡(lǐ),你(nǐ)需要(y ✘ào)尋求一(yī)種平衡—&mda← →"sh;不(bù)要(yào)盲目地(dì)φ✘↑使用(yòng)data-test屬性标記每個(gè)元α♦素。例如(rú),如(rú)果你(nǐ)想點擊一(yī)個(gè)購<&(gòu)買特定産品的(de)按鈕,那(nà)↓∑麽你(nǐ)真正需要(yào)的(de)©≤α‌隻是(shì)定位某個(gè)包含那(nà)款産品及購(gòu)♥Ωε買按鈕的(de)元素。

  添加data-test-product屬性後,$±₩σ你(nǐ)就(jiù)能(néng)夠使用(y♠‍λòng)一(yī)個(gè)像[data-test-product=&#®γ←♥39;1234'] input[ty∏∞pe='submit']這(zhè ≥≥)樣的(de)CSS選擇器(qì)定位産品1234的( ₹↔de)購(gòu)買按鈕了(le)。

  這(zhè)意味著(zhe)你(nǐ)必須修改隻為αβ(wèi)測試而存在的(de)标記,就(jiù)是(shì)說(shuō)→£¶,為(wèi)了(le)獲得(de)你(nǐ)提供給他(tā)們的(de)用(γ  yòng)戶體(tǐ)驗,用(yòng)戶要(yào)下(xi∑<∞à)載一(yī)些(xiē)他(tā)們不(bù)需要(yào)的(de ☆&₩)字節。這(zhè)是(shì)一(yī)種Ω×σ÷平衡,但(dàn)比糟糕的(de)測試覆蓋率(對(duì)用( ÷βyòng)戶的(de)傷害遠(yuǎn)遠(yuǎn)超γ₹過了(le)HTML中多(duō)一(yī)些(xiē)額外±∑↓(wài)的(de)字節)要(yào)好(hǎo)。隻是(shì)得(de‍♥πε)恰到(dào)好(hǎo)處。

  當頁面上(shàng)有(yǒu)改變頁面內(nèi)容而又(yòuα•‌α)不(bù)重新加載的(de)交互(換句話(huà)↕δ☆¥說(shuō),使用(yòng)JavaScript)時(s§♥hí),這(zhè)項技(jì)術(shù)就(jiù)更加重要(yà•≥‌¶o)了(le)。

  處理(lǐ)交互

  當每次點擊都(dōu)重新加載頁面時(shí),端到(dào)端測£∞®試更可(kě)靠,因為(wèi)底層工(gōng)具知(zhī)↑>‍γ道(dào)要(yào)等待一(yī)個(gè)頁面重新加載。當用(y‌₽αòng)戶交互隻是(shì)改變DOM時(shí),難度就(jiù)αδγ©大(dà)了(le),因為(wèi)工(β<≈gōng)具不(bù)知(zhī)道(dào ✔↔)什(shén)麽“事(shì)情”₩♣¥正在發生(shēng),也(yě)就(jiù)無法“等待事"✔‍(shì)情完成”。

  當測試需要(yào)同一(yī)個(gè)不£±(bù)會(huì)根據用(yòng)戶動作(zuò)重新÷φ€加載的(de)頁面交互時(shí),就(jiù)需要(y×↕‌ào)一(yī)種方法能(néng)夠在開(kāi)始斷言發生(shē'®γ&ng)了(le)什(shén)麽之前等待DOM操作(zuò)完成。如("​<rú)果不(bù)等待,那(nà)麽如(rú)果測試開(kāi)始斷言時(£☆$shí)DOM還(hái)沒有(yǒu)更新,測試就(jiù)會÷λπ (huì)無謂地(dì)失敗。

  就(jiù)像在标記中使用(yòng)标識定位要(yào)β¶操作(zuò)的(de)DOM元素一(yī)樣,我們也 ☆"(yě)可(kě)以把它們用(yòng)在這(zhè)裡(lǐ)。任∑♠∑何新增或變化(huà)的(de)标記都(dōu)應該有(yǒu)某種在交互失敗​≈或沒有(yǒu)發生(shēng)的(de)情況下(xià)不(bù)會®₽(huì)出現(xiàn)的(de)标識。換句話(huà)說(®☆<πshuō),你(nǐ)不(bù)必為(wèi)了(le)等待DOM事✘≈≤≠(shì)件(jiàn)而在測試中進行(xíng)休眠調用<φ(yòng)——DOM中應該包σ¥♣¶含可(kě)供測試顯式等待的(de)标識。

  例如(rú),假設我們想要(yào)測試一(yī)個(gè)動作(γ↕γ zuò)為(wèi)用(yòng)戶生(shēng♥ •±)成了(le)一(yī)條成功的(de)消息。假設實現(xiàn)方法≠≥是(shì)發出一(yī)個(gè)AJAX請(qǐng'φ)求,當調用(yòng)結束時(shí)向DO÷©M中插入一(yī)條消息。一(yī)個(gè)基本的(de)實現(xiàn₽®)可(kě)以像下(xià)面這(zhè)樣做(zuò):

  function purchase(productId×₽™$) {

  $.post(

  "/products/&quoλ→≤≥t;,

  { "id": produc λ★tId }

  ).done(function() {

  $(".header"€↔γ≤;).html(

  "

  Your order was placed

  ");

  }).fail(function() {

  $(".header").html(

  "

  There was a problem

  ");

  });

  你(nǐ)可(kě)以通(tōng)過配置讓測試等待一(yī∞ € )個(gè)使用(yòng)了(le)CSS類al↑≤ert-success的(de)元素出現(xià ✔↑ n),然後斷言它的(de)內(nèi)容。這(zhè)意味著(z→∞he),如(rú)果頁面需要(yào)任何∏₽↑其他(tā)使用(yòng)那(nà)個(gè)類&÷≤的(de)元素,那(nà)麽測試就(ji∑↑←>ù)會(huì)不(bù)可(kě)靠或被破壞。雖然你"★(nǐ)可(kě)以将其限制(zhì)在HTML頭裡(lǐ),但< (dàn)這(zhè)隻是(shì)緩兵(bīng)→δ§♥之計(jì)。

  作(zuò)為(wèi)替代,可(kě)以使用(yòn•♠•¶g)data-test-屬性:

  function purchase(productId) {Ω‍

  $.post(

  "/products/&quo± ∑t;,

  { "id": productId }∑♦β♣

  ).done(function() {

  $(".header").htm®ε↓l(

  "

  Your order was placed

  ");

  }).fail(function() {

  $(".header").html(

  "

  There was a problem

  ");

  });

  雖然這(zhè)增加了(le)标記的(de)<"$字節,但(dàn)它讓你(nǐ)可(kě)以編寫一(yβ✔↑"ī)個(gè)能(néng)夠不(bù)受某些(xiē)視§λ≠(shì)覺變化(huà)影(yǐng)響的♥δ(de)可(kě)靠測試。隻要(yào)頁面流程是(shì)在一(yīσ₹)次成功的(de)購(gòu)買後顯示一(yī)​♠♣條消息,那(nà)麽可(kě)視(shì)化(huà)實現(Ωφ↕∏xiàn)就(jiù)可(kě)以修改而又↓↑∑≤(yòu)不(bù)破壞測試。這(zhè)是(shì)你(nǐ)想™←要(yào)的(de),這(zhè)是(sh¥₹ì)一(yī)種權衡。你(nǐ)也(yě)¶β↔®可(kě)以犧牲掉這(zhè)份自(zì)信,創↑σ✘建較小(xiǎo)較起碼的(de)标記,但(δ£σ dàn)當顯示效果變化(huà)時(shí),你(nǐ)要(yà∑α≤÷o)麽花(huā)時(shí)間(jiān)修複測試,被迫手動 ™δQA,要(yào)麽就(jiù)發布沒有(yǒu)經過充分(fēn©§★∑)測試的(de)軟件(jiàn)。

  如(rú)今的(de)端到(dào)端測試工(gōng)具,如(§•∏rú)Capybara,包含你(nǐ)需要(yào)€φδ的(de)所有(yǒu)功能(néng)。它提供了(le)★✘$方法,可(kě)以在繼續測試過程之前等待DOM元素出現(₽λ↕xiàn),斷言頁面特定部分(fēn)的(de)內(nèi)∑$容,同表單元素交互。大(dà)多(duō)數(shù)其≠♣φβ他(tā)Web應用(yòng)程序棧都(dōu)提供了(le)類似₩φ的(de)工(gōng)具。不(bù)管怎樣,你(nǐ)可(kě)"÷以将測試庫與像PhantomJS這(zhè)樣的(‍•de)無界面浏覽器(qì)結合,從(cóng)而使端到(dào)♣↕ ✔端測試出奇地(dì)快(kuài)速可(kě)靠。

  還(hái)有(yǒu)一(yī)點值得(de)注γ™✘意,就(jiù)是(shì)在一(yī)個(gè)分(®σδfēn)布式的(de)環境中如(rú)何完成這(zhè)項工(g÷≠™&ōng)作(zuò)。

  當“應用(yòng)&rdq ¶uo;多(duō)于一(yī)個(gè)

  當對(duì)單個(gè)整體(tǐ∑₩)系統進行(xíng)測試時(shí),上(shàngα£γδ)述技(jì)術(shù)就(jiù)完全夠用(yòng)了(l÷®♦e)。然而,如(rú)果是(shì)對(d≠​>uì)一(yī)個(gè)較為(wèi)分(fē↕₹π↕n)散的(de)系統進行(xíng)測試,情況就(jiù)要α∞¶↑(yào)複雜(zá)些(xiē)了(le)。假∏→設你(nǐ)正緻力于一(yī)個(gè)面向客戶的(de)應用♦↕₩(yòng)程序,但(dàn)它必須從(cóng)另一(yφ ī)個(gè)系統獲取庫存數(shù)據。你(nǐ)如(rú)何為(wèi&&)此編寫一(yī)個(gè)測試呢(ne)?

  首先,記住你(nǐ)在測試什(shén)麽。端到(dào)端♥®™測試是(shì)測試用(yòng)戶交互。這(zh•←↕è)意味著(zhe),端到(dào)端測試不(↔•←♥bù)用(yòng)負責斷言遠(yuǎn)程服務的(d≥₹≤e)功能(néng),也(yě)不(bù∑↓ε)用(yòng)負責斷言應用(yòng)程序正确地(dì)消費(fè§☆↔≈i)了(le)那(nà)個(gè)遠(yuǎn)程服務。

  測試服務消費(fèi)的(de)較佳方式是(shì)使用∑↔©✘(yòng)“消費(fèi)者驅動的(₹✔de)契約(consumer-driven cont≤λσracts)”,這(zhè)是(sh≤∞ì)一(yī)種單元測試的(de)形式(至少(shǎo)在↓∑©這(zhè)篇博文(wén)中我所做(zuò)的(de¥∏←)寬泛界定中是(shì)這(zhè)樣)&↔>™。

  對(duì)于在端到(dào)端測試‍∑中如(rú)何模拟遠(yuǎn)程服務,至此仍然§•沒有(yǒu)定論。你(nǐ)可(kě)以搭建™♥該服務的(de)一(yī)個(gè)實際版本,但(dàn)這(zhè)并不✘₽®(bù)是(shì)很(hěn)好(hǎ✘£o)。你(nǐ)較終不(bù)得(de)不(bù)管理(l↑≥ǐ)那(nà)個(gè)服務的(de)內(nèi)部數(shù)據存€ ‌儲以及它所依賴的(de)服務。那(nà)會(huì)使複雜(zá)性迅速↔∑ 增加,難以管理(lǐ)。

  一(yī)個(gè)常見(jiàn)的(de ₽≤₩)選擇是(shì)使用(yòng)一(yī)個(gè)HTTP層的(de)模€£拟系統。在Ruby中,VCR是(shì)一(yī)款具備這(zhè¶‍)種功能(néng)的(de)工(gōng)具。你(nǐ)錄制(zhì)同Ω ✘真實服務交互以建立HTTP協議(yì)往返的(de)過程,在随↓>後運行(xíng)測試時(shí),模拟系統會(huì)回放π♥✔(fàng)錄制(zhì)好(hǎo)的(de)$$₹交互,而不(bù)必使用(yòng)網絡。如(rú)果單元測試覆蓋了(le)™λ服務的(de)正确消費(fèi),那(nà)麽這(zhè)對(duì)♣∑♣于端到(dào)端測試就(jiù)會(huì)很(h<≥ěn)有(yǒu)效。

  另一(yī)個(gè)選擇是(shì)搭建一(yī)個(gè)經過簡化(•→₽huà)的(de)模拟服務,該服務返回預先準備好(hǎo)的(de☆∑♣)數(shù)據。應用(yòng)會(huì)像平常一(yī)樣進行β±>'(xíng)HTTP調用(yòng),但(dàn)調用(yòng)₹↑的(de)是(shì)一(yī)個(gè)預先準ε✔備好(hǎo)、隻向應用(yòng)返回靜♠♦"¥(jìng)态已知(zhī)數(shù)據的(de)服務。這(zhè)需要™→"(yào)提前做(zuò)些(xiē)配置,但(dàn)對"✘(duì)簡單的(de)服務交互很(hěn)有(yǒu)效。如(&←•"rú)果應用(yòng)程序需要(yào≥≥✔)在服務中存儲狀态,并有(yǒu)一(yī)個(gè)漫長(ch↑✘áng)的(de)往返“對(duì)話(huà)”,那↓$≥∞(nà)麽這(zhè)項技(jì)術(shù)就(jiù)要(yào)Ω ' 難一(yī)些(xiē)了(le)。

  我的(de)建議(yì)是(shì)首∑<→先嘗試模拟HTTP,因為(wèi)那(nà)既☆ ≠∏簡單又(yòu)快(kuài)捷。

  現(xiàn)在,我們知(zhī)道(₩÷dào)在端到(dào)端測試中測試什(shéε✔ ↔n)麽以及如(rú)何測試,那(nà)麽單元測試δ≤¥✔呢(ne)?

  單元測試

  回想一(yī)下(xià),對(duì)于什(shφ₩én)麽應該進行(xíng)端到(dào)端的(de)測試,我♣Ω們的(de)标準是(shì)用(yòng✔♥γ¥)戶流程。其思想是(shì),雖然整個(g÷$¥è)系統有(yǒu)許多(duō)可(kě)能(≤‌¥₩néng)的(de)邏輯流程,但(dàn)能(néng)δ‍對(duì)用(yòng)戶體(tǐ)驗産✔✔"®生(shēng)影(yǐng)響的(de)要(yào)少(↔↔ ≤shǎo)很(hěn)多(duō)。單元測試就(jiσ♦ ♠ù)是(shì)要(yào)測試那(nà)些(xiē)邏輯流程的(de)剩餘 >>≥部分(fēn)。

  這(zhè)讓我們可(kě)以快(kuài)速可(kěπ≈♦§)靠地(dì)斷言系統大(dà)部分(fē∏♠n)功能(néng)的(de)正确行(xín®↔g)為(wèi)。換句話(huà)說(shuō)≥π↓,雖然我們可(kě)以使用(yòng)端到(€φ≠£dào)端測試斷言整個(gè)系統中每個(gè &<)可(kě)能(néng)的(de)流程¥<∏ ,但(dàn)那(nà)沒有(yǒu)必要(yào),而且會(hu↔≤•ì)非常緩慢(màn)和(hé)脆弱。

  例如(rú),假設一(yī)個(gè)結算(suàn)功能(nén↔♦§​g)有(yǒu)兩個(gè)用(yòng)戶流程:一(yī)個(gα è)是(shì)購(gòu)買成功,一(yī)個(gè¶§&)是(shì)購(gòu)買失敗,用(yòng)戶必φ↔須重試。那(nà)會(huì)有(yǒu)兩個(gè)端到(dào)端測∞✘試。讓我們進一(yī)步假設,後台有(yǒu)如(rú'©♦)下(xià)可(kě)能(néng)性:

  客戶的(de)信用(yòng)卡正确扣™♠款;

  與客戶銀(yín)行(xíng)的(de)通(tōng)信π£存在問(wèn)題,但(dàn)我們想假∞φ裝它是(shì)成功的(de),并在稍後扣款;

  客戶的(de)信用(yòng)卡被拒絕;

  客戶的(de)信用(yòng)卡過期。

  這(zhè)是(shì)四個(gè)流程,所以我們希望有(yǒu)四個(± ₹€gè)單元測試可(kě)以斷言其中每一(yī)種情況都(dōu)得(de¥§ φ)到(dào)了(le)正确處理(lǐ)。是(sh"•↔ì)的(de),會(huì)有(yǒu)重複覆蓋。® ÷在端到(dào)端測試中,我們可(kě)能(néng)會(huì)創建★≈ε成功扣款和(hé)拒絕兩個(gè)測試來(lái)處理(lǐ)該功能(n‍¥ éng)的(de)兩個(gè)用(yòngα ↓δ)戶流程,因此,當編寫單元測試時(shí),我們的(de)覆‌‍← 蓋率就(jiù)會(huì)超過理(lǐ)論上(shà≤>ng)的(de)需要(yào)。

  再一(yī)次,這(zhè)是(sh∞↕↕™ì)一(yī)種權衡,但(dàn)重要(yào)的(de)Ω€是(shì),單元測試可(kě)以很(hěn)好(hǎo)地(dì)覆蓋你&₩'(nǐ)的(de)類。這(zhè)就(jiù)允許它們改變位置、用(yδ‌↑Ωòng)途,而且更容易修改。

  關于如(rú)何編寫單元測試,有(yǒu)許多(duō)許多(duō)的★π♥✔(de)理(lǐ)論,遠(yuǎn)遠(yuǎn)超出了(l↑♥e)我們這(zhè)裡(lǐ)的(de)討(tǎo)論範圍。我的(d₽₩π≤e)建議(yì)是(shì)采用(yòng)一(yī) ™π₽種對(duì)你(nǐ)有(yǒu)用(yòng)同時(shí)‌✔也(yě)容易跟别人(rén)解釋的(de)技(jì)術(s£≤ hù),并一(yī)直使用(yòng)。

  對(duì)于單元測試,較困難的(de♣ελ)部分(fēn)是(shì)決定代碼設計(jì)要(yào)在多(duō)→∞大(dà)程度上(shàng)為(wèi)測試考慮。這(zhè)✘φ®♥就(jiù)類似我們如(rú)何為(wèi)了(le)測試向HTM≠£±₽L中增加屬性和(hé)其他(tā)标識——那≈™γ≤(nà)些(xiē)工(gōng)件(ji©Ω™àn)隻是(shì)因為(wèi)我們要(yào)測試而存在。在編寫單π★元測試時(shí),你(nǐ)會(huì)面臨同樣的(dγ≤e)選擇。

  例如(rú),假設Purchaser類實現(xiàn)了(l¶βδe)信用(yòng)卡扣款代碼。假設它将使用(yòn★Ωg)第三方提供的(de)AwesomePayments進行§ε♦£(xíng)實際地(dì)扣款。

  class Purchaser

  def charge(purchase)

  AwesomePayments.cha"​×rge(purchase.customer.id,purchase.a™≤‌mount)

  rescue => ex

  try_again_later(purchase.id)

  end

  # ...

  end

  上(shàng)述代碼清晰易懂(dǒng),在不(bù)需要(yà∑εo)單元測試的(de)情況下(xià),這(zhè)可€ ≠(kě)能(néng)是(shì)較理(lǐ)想的(de)設計(♥♦€×jì)了(le)。然而,為(wèi)了(le₩↔§↑)讓測試更簡單,我們可(kě)能(néng)想控制(£¶zhì)AwesomePayments的(de)實例:

  class Purchaser

  def initialize(awesome_payments = A↑≥§$wesomePayments)

  @awesome_payments = a ↔wesome_payments

  end

  def charge(purchasεφσ∏e)

  @awesome_payments.cha♣ ∞'rge(purchase.customer.id,purchase×<.amount)

  rescue => ex

  try_again_later(purchase.id)

  end

  end

  現(xiàn)在,就(jiù)可(kě)以在測試時'σ↔♣(shí)傳入AwesomePayments✘$的(de)模拟實現(xiàn),從(cóng®δ)而更好(hǎo)地(dì)控制(zhì)測試。測試已經影(y≥∑ǐng)響了(le)我們的(de)設計(jì)(雖然這(z<✔₽hè)裡(lǐ)的(de)影(yǐng)響比較小(xiǎo))。你(nǐ)甚至→☆可(kě)以說(shuō),這(zhè)個(gè)類就(jiù)是(<"shì)更好(hǎo)的(de)代碼。但(dàn)情況并非←≤總是(shì)如(rú)此。

  我會(huì)使用(yòng)同你(nǐ)處理(lǐ)端到(dào☆ '↑)端測試一(yī)樣的(de)标準:做(z₩>∏¥uò)讓生(shēng)活更輕松的(de)事(shì),但(dàn)不(b↔>‌♦ù)要(yào)做(zuò)過頭,務必要(yào)恰到(שδdào)好(hǎo)處。

相(xiàng)關文(wén)章(zhā>✔ ng)推薦
下(xià)一(yī)代工(gōng)業(yè)進步被稱為(<<∏wèi)工(gōng)業(yè)4.0,旨在将傳統行(xíng)業(yè)¥< (如(rú)自(zì)動化(huà))互聯>÷互通(tōng)并實現(xiàn)計(jì)算(suàn)機(jīΩ•)化(huà)。工(gōng)業(yè)4.0的(de)目标是(s ↓δhì)使工(gōng)廠(chǎng)變得® (de)更加智能(néng),提高(gāo)适應₹&性和(hé)資源效率,以及改善工(gōng)廠(chǎn↔♠g)之間(jiān)供...
您正在尋找能(néng)夠将您令人(rén)驚歎的(de)應÷★用(yòng)程序想法變為(wèi)現(xiàn)實•✔的(de)人(rén)。我應該聘請(qǐng)軟件(®φπ→jiàn)公司還(hái)是(shì)兼職開(kāi)發者?這(zhè)可♣♣÷↓(kě)能(néng)是(shì)每個(gè)新↓ 晉産品所有(yǒu)者問(wèn)自(zì)己的(de)最常見(£≥jiàn)問(wèn)題。在開(kāi)始開σγ (kāi)發過程之前,您需要(yào)...
從(cóng)頭開(kāi)始構建網站(σ∑✘zhàn)并托管和(hé)維護或改造舊(jiù)網站(zhàn)"'需要(yào)聘請(qǐng)一(yī)支擁有(yǒu)技(jì)'♥Ω£能(néng)和(hé)專業(yè)知(zhī)識​‍§的(de)團隊。如(rú)果您不(bù)想進一(yī)步擴大(dà)團隊γλ♥,不(bù)想經曆招聘大(dà)手筆(bǐ),或者想降σ♠₽低(dī)離(lí)岸成本,北(běi)京軟件(jiàn)開 ≥←✘(kāi)發外(wài)包...
物(wù)聯網 ( IoT ) 概念首次出現(xià₹✔<n)時(shí),曾有(yǒu)大(dà)膽預測稱,到(dào) 2020©₩← 年(nián),物(wù)聯網連接設備≤♣₹數(shù)量将達到(dào) 500 億甚§♦✘至數(shù)萬億。這(zhè)些(xiē)極高(gāo≠✘)的(de)估值引發了(le)炒作(zuò),但(dàn)​¶≈ 最終被證明(míng)...
下(xià)一(yī)代工(gōng)業(yè)進步被稱‍₹為(wèi)工(gōng)業(yè)4.0,旨在将傳統行("← λxíng)業(yè)(如(rú)自(zì)動化(huΩ$"¶à))互聯互通(tōng)并實現(xiàn)計(jì)算(>→×suàn)機(jī)化(huà)。工(gōng)業(yè)4.€♥0的(de)目标是(shì)使工(gōng)廠(ch→•≥®ǎng)變得(de)更加智能(néng),提高(gāo)适應性和‌&(hé)資源效率,以及改善工(gōng)廠≈♥(chǎng)之間(jiān)供...
企業(yè)需要(yào)強大(dà)且可(k‍§φě)靠的(de)在線形象才能(néng)取得(de)成功。Magento 已成₽¶★±為(wèi)領先的(de)電(diàn)子(zǐ)商務平↕α↑∑台,為(wèi)各種規模的(de)企業(yè)提供強♣♦₽✔大(dà)的(de)功能(néng)和(hé)定制(zh‌σ£↓ì)選項。對(duì)于希望通(tōng)過基于 Magento ...
北(běi)京軟件(jiàn)開(kāi)發公司認為(wèi)信息和(h¶©é)軟件(jiàn)技(jì)術(shù)的(dσ‍e)重點是(shì)研究和(hé)經驗,...
  大(dà)數(shù)據是(shì)時(shí)下(xià)較熱(✔ ∞rè)的(de)詞之一(yī),什(shén)δ €麽是(shì)大(dà)數(shù)據呢( δne)?首先是(shì)大(dà),要(yào)有(yǒu)海₽™★α(hǎi)量的(de)數(shù)據,更重要(yào)的(de)是(shì)∏↑ε數(shù)據挖掘,在CRM管理(lǐ)中數(shù)據挖掘大(d©♥à)有(yǒu)可(kě)為(wèi),我們©"₹可(kě)以利用(yòng)數(shù)據挖掘♠★→技(jì)術(shù)對(duì)顧客的(de)購(gòu)買行(xíng)€↑♠↕為(wèi)和(hé)曆...
您正在尋找能(néng)夠将您令人(rén)驚歎的(d¶<e)應用(yòng)程序想法變為(wèi)現(x✘<≠iàn)實的(de)人(rén)。我應該聘請(qǐng)軟件(jiànλ♦)公司還(hái)是(shì)兼職開(kāi)發∞&✔≈者?這(zhè)可(kě)能(néng)是(shì)每個(g>∑♣↑è)新晉産品所有(yǒu)者問(wèn)自(zì)己的(de)最常見(jiàn •₹™)問(wèn)題。在開(kāi)始開(kāi)發過程之前,您需要(yγ↕ ào)...
北(běi)京軟件(jiàn)開(kāi)發當大(dà)數(sα→hù)據成為(wèi)一(yī)種資源...
北(běi)京APP開(kāi)發公司金(jīn)融APP開(k₹‍āi)發解決方案随著(zhe)人(rén)們的(de)生(sΩ©↔¥hēng)活質量不(bù)斷提升,經濟條件(≥→jiàn)不(bù)斷優化(huà),金(jīn)融行(xí¶"πng)業(yè)也(yě)随之變得(de)<₩≠ 越來(lái)越火(huǒ)熱(rè),而近(jìnλ↕§)幾年(nián),智能(néng)化(huà)的(de)時(shí)代££,移動互聯網不(bù)斷的(de)發展與更新,讓...
北(běi)京軟件(jiàn)開(kāi©♦Ω)發公司百家(jiā)争鳴2016熱(rè)門(Ω∞‌≠mén)運動軟件(jiàn)...