W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
Web應(yīng)用程序越來越復(fù)雜,這意味著有更多的可能出錯。測試是幫助我們提高代碼質(zhì)量、降低錯誤的最好方法和工具之一。
單元測試(unit testing)指的是以軟件的單元為單位,對軟件進行測試。單元(unit)可以是一個函數(shù),也可以是一個模塊或組件。它的基本特征就是,只要輸入不變,必定返回同樣的輸出。
單元測試這個詞,本身就暗示,軟件應(yīng)該以模塊化結(jié)構(gòu)存在。每個模塊的運作,是獨立于其他模塊的。一個軟件越容易寫單元測試,往往暗示著它的模塊化結(jié)構(gòu)越好,各模塊之間的耦合就越弱;越難寫單元測試,或者每次單元測試,不得不模擬大量的外部條件,很可能暗示軟件的模塊化結(jié)構(gòu)越差,模塊之間存在較強的耦合。
單元測試的要求是,每個模塊都必須有單元測試,而軟件由模塊組成。
單元測試通常采取斷言(assertion)的形式,也就是測試某個功能的返回結(jié)果,是否與預(yù)期結(jié)果一致。如果與預(yù)期不一致,就表示測試失敗。
單元測試是函數(shù)正常工作、不出錯的最基本、最有效的方法之一。 每一個單元測試發(fā)出一個特定的輸入到所要測試的函數(shù),看看函數(shù)是否返回預(yù)期的輸出,或者采取了預(yù)期的行動。單元測試證明了所測試的代碼行為符合預(yù)期。
單元測試有助于代碼的模塊化,因此有助于長期的重用。因為有了測試,你就知道代碼是可靠的,可以按照預(yù)期運行。從這個角度說,測試可以節(jié)省開發(fā)時間。單元測試的另一個好處是,有了測試,就等于就有了代碼功能的文檔,有助于其他開發(fā)者了解代碼的意圖。
單元測試應(yīng)該避免依賴性問題,比如不存取數(shù)據(jù)庫、不訪問網(wǎng)絡(luò)等等,而是使用工具虛擬出運行環(huán)境。這種虛擬使得測試成本最小化,不用花大力氣搭建各種測試環(huán)境。
單元測試的步驟
集成測試(Integration test)指的是多個部分在一起測試,比如在一個測試數(shù)據(jù)庫上,測試數(shù)據(jù)庫連接模塊。
功能測試(Functional test)指的是,自動測試整個應(yīng)用程序的某個功能,比如使用Selenium工具自動打開瀏覽器運行程序。
TDD是“測試驅(qū)動的開發(fā)”(Test-Driven Development)的簡稱,指的是先寫好測試,然后再根據(jù)測試完成開發(fā)。使用這種開發(fā)方式,會有很高的測試覆蓋率。
TDD的開發(fā)步驟如下。
TDD開發(fā)的測試覆蓋率通常在90%以上,這意味著維護代碼和新增特性會非常容易。因為測試保證了你可以信任這些代碼,修改它們不會破壞其他代碼的運行。
TDD接口提供以下四個方法。
下面代碼是測試計數(shù)器是否加1。
suite('Counter', function() {
test('tick increases count to 1', function() {
var counter = new Counter();
counter.tick();
assert.equal(counter.count, 1);
});
});
BDD是“行為驅(qū)動的開發(fā)”(Behavior-Driven Development)的簡稱,指的是寫出優(yōu)秀測試的最佳實踐的總稱。
BDD認(rèn)為,不應(yīng)該針對代碼的實現(xiàn)細(xì)節(jié)寫測試,而是要針對行為寫測試。BDD測試的是行為,即軟件應(yīng)該怎樣運行。
BDD接口提供以下四個方法。
下面是測試計數(shù)器是否加1的BDD寫法。
describe('Counter', function() {
it('should increase count by 1 after calling tick', function() {
var counter = new Counter();
var expectedCount = counter.count + 1;
counter.tick();
assert.equal(counter.count, expectedCount);
});
});
斷言是判斷實際值與預(yù)期值是否相等的工具。
斷言有assert、expext、should三種風(fēng)格,或者稱為三種寫法。
// assert風(fēng)格
assert.equal(event.detail.item, '(item).);
// expect風(fēng)格
expect(event.detail.item).to.equal('(item)');
// should風(fēng)格
event.detail.item.should.equal('(item)');
Chai.js是一個很流行的斷言庫,同時支持上面三種風(fēng)格。
(1) assert風(fēng)格
var assert = require('chai').assert;
var foo = 'bar';
var beverages = { tea: [ 'chai', 'matcha', 'oolong' ] };
assert.typeOf(foo, 'string', 'foo is a string');
assert.equal(foo, 'bar', 'foo equal `bar`');
assert.lengthOf(foo, 3, 'foo`s value has a length of 3');
assert.lengthOf(beverages.tea, 3, 'beverages has 3 types of tea');
上面代碼中,assert方法的最后一個參數(shù)是錯誤提示信息,只有測試沒有通過時,才會顯示。
(2)expect風(fēng)格
var expect = require('chai').expect;
var foo = 'bar';
var beverages = { tea: [ 'chai', 'matcha', 'oolong' ] };
expect(foo).to.be.a('string');
expect(foo).to.equal('bar');
expect(foo).to.have.length(3);
expect(beverages).to.have.property('tea').with.length(3);
(3)should風(fēng)格
var should = require('chai').should();
var foo = 'bar';
var beverages = { tea: [ 'chai', 'matcha', 'oolong' ] };
foo.should.be.a('string');
foo.should.equal('bar');
foo.should.have.length(3);
beverages.should.have.property('tea').with.length(3);
Mocha是一個測試框架,也就是運行測試的工具。它使用下面的命令安裝。
$ npm install -g mocha
Mocha自身不帶斷言庫,所以還需要安裝一個斷言庫,這里選用Chai.js。
$ npm install -g chai
Mocha默認(rèn)執(zhí)行test目錄的腳本文件,所以我們將所有測試腳本放在test子目錄。
Mocha允許指定測試腳本文件,可以使用通配符,同時指定多個文件。
$ mocha --reporter spec spec/{my,awesome}.js
$ mocha --ui tdd test/unit/*.js etc
如果希望測試非存放于test子目錄的測試用例,可以在test子目錄中新建Mocha的配置文件mocha.opts。在該文件中寫入以下內(nèi)容。
server-tests
上面代碼指定Mocha默認(rèn)測試server-tests子目錄的測試腳本。
server-tests
--recursive
上面代碼中,--recursive參數(shù)指定同時運行子目錄中的測試用例腳本。
report參數(shù)用于指定Mocha的報告格式。
$ mocha --reporter spec server-test/*.js
上面代碼指定報告格式是spec。
grep參數(shù)用于搜索測試用例的名稱(即it方法的第一個參數(shù)),然后只執(zhí)行匹配的測試用例。
$ mocha --reporter spec --grep "Fnord:" server-test/*.js
上面代碼只測試名稱中包含“Fnord:”的測試用例。
invert參數(shù)表示只運行不符合條件的測試腳本。
$ mocha --grep auth --invert
測試腳本中,describe方法和it方法都允許調(diào)用only方法,表示只運行某個測試套件或測試用例。
describe("using only", function() {
it.only("this is the only test to be run", function() {
});
it("this is not run", function() {
});
});
上面代碼中,只有第一個測試用例會運行。
describe方法和it方法還可以調(diào)用skip方法,表示跳過指定的測試套件或測試用例。
describe("using only", function() {
it.skip("this is the only test to be run", function() {
});
it("this is not run", function() {
});
});
上面代碼中,只有第二個測試用例會執(zhí)行。
如果測試用例包含異步操作,可以done方法顯式指定測試用例的運行結(jié)束時間。
it('logs a', function(done) {
var f = function(){
console.log('logs a');
done();
};
setTimeout(f, 500);
});
上面代碼中,正常情況下,函數(shù)f還沒有執(zhí)行,Mocha就已經(jīng)結(jié)束運行了。為了保證Mocha等到測試用例跑完再結(jié)束運行,可以手動調(diào)用done方法
WebDriver是一個瀏覽器的自動化框架。它在各種瀏覽器的基礎(chǔ)上,提供一個統(tǒng)一接口,將接收到的指令轉(zhuǎn)為瀏覽器的原生指令,驅(qū)動瀏覽器。
WebDriver由Selenium項目演變而來。Selenium是一個測試自動化框架,它的1.0版叫做Selenium RC,通過一個代理服務(wù)器,將測試腳本轉(zhuǎn)為JavaScript腳本,注入不同的瀏覽器,再由瀏覽器執(zhí)行這些腳本后返回結(jié)果。WebDriver就是Selenium 2.0,它對每個瀏覽器提供一個驅(qū)動,測試腳本通過驅(qū)動轉(zhuǎn)換為瀏覽器原生命令,在瀏覽器中執(zhí)行。
DesiredCapabilities對象用于定制測試環(huán)境。
WebDriver提供以下方法操作瀏覽器。
close():退出或關(guān)閉當(dāng)前瀏覽器窗口。
driver.close();
quit():關(guān)閉所有瀏覽器窗口,中止當(dāng)前瀏覽器driver和session。
driver.quit();
getTitle():返回當(dāng)前網(wǎng)頁的標(biāo)題。
driver.getTitle();
getCurrentUrl():返回當(dāng)前網(wǎng)頁的網(wǎng)址。
driver.getCurrentUrl();
getPageSource():返回當(dāng)前網(wǎng)頁的源碼。
// 斷言是否含有指定文本
assert(driver.getPageSource().contains("Hello World"),
"預(yù)期含有文本Hello World");
click():模擬鼠標(biāo)點擊。
// 例一
driver.findElement(By.locatorType("path"))
.click();
// 例二
driver.get("https://www.google.com");
driver.findElement(By.name("q"))
.sendKeys("webDriver");
driver.findElement(By.id("sblsbb"))
.click();
clear():清空文本輸入框。
// 例一
driver.findElement(By.locatorType("path")).clear();
// 例二
driver.get("https://www.google.com");
driver.findElement(By.name("q"))
.sendKeys("webDriver");
driver.findElement(By.name("q"))
.clear();
driver.findElement(By.name("q"))
.sendKeys("testing");
sendKeys():在文本輸入框輸入文本。
driver.findElement(By.locatorType("path"))
.sendKeys("your text");
submit():提交表單,或者用來模擬按下回車鍵。
// 例一
driver.findElement(By.locatorType("path"))
.submit();
// 例二
driver.get("https://www.google.com");
driver.findElement(By.name("q"))
.sendKeys("webdriver");
element.submit();
findElement():返回選中的第一個元素。
driver.get("https://www.google.com");
driver.findElement(By.id("lst-ib"));
findElements():返回選中的所有元素(0個或多個)。
// 例一
driver.findElement(By.id("searchbox"))
.sendKeys("webdriver");
driver.findElements(By.xpath("http://div[3]/ul/li"))
.get(0)
.click();
// 例二
driver.findElements(By.tagName("select"))
.get(0)
.findElements(By.tagName("option"))
.get(3)
.click()
.get(4)
.click()
.get(5)
.click();
// 例三:獲取頁面所有鏈接
var links = driver
.get("https://www.google.com")
.findElements(By.tagName("a"));
var linkSize = links.size();
var linksSrc = [];
console.log(linkSize);
for(var i=0;i<linkSize;i++) {
linksSrc[i] = links.get(i).getAttribute("href");
}
for(int i=0;i<linkSize;i++){
driver.navigate().to(linksSrc[i]);
Thread.sleep(3000);
}
可以使用size()
,查看到底選中了多少個元素。
WebDriver提供8種定位器,用于定位網(wǎng)頁元素。
下面是一個使用id定位器,選中網(wǎng)頁元素的例子。
driver.findElement(By.id("sblsbb")).click();
以下方法屬于網(wǎng)頁元素的方法,而不是webDriver實例的方法。需要注意的是,有些方法是某些元素特有的,比如只有文本框才能輸入文字。如果在網(wǎng)頁元素上調(diào)用不支持的方法,WebDriver不會報錯,也不會給出給出任何提示,只會靜靜地忽略。
getAttribute():返回網(wǎng)頁元素指定屬性的值。
driver.get("https://www.google.com");
driver.findElement(By.xpath("http://div[@id='lst-ib']"))
.getAttribute("class");
getText():返回網(wǎng)頁元素的內(nèi)部文本。
driver.findElement(By.locatorType("path")).getText();
getTagName():返回指定元素的標(biāo)簽名。
driver.get("https://www.google.com");
driver.findElement(By.xpath("http://div[@class='sbib_b']"))
.getTagName();
isDisplayed():返回一個布爾值,表示元素是否可見。
driver.get("https://www.google.com");
assert(driver.findElement(By.name("q"))
.isDisplayed(),
'搜索框應(yīng)該可選擇');
isEnabled():返回一個布爾值,表示文本框是否可編輯。
driver.get("https://www.google.com");
var Element = driver.findElement(By.name("q"));
if (Element.isEnabled()) {
driver.findElement(By.name("q"))
.sendKeys("Selenium Essentials");
} else {
throw new Error();
}
isSelected():返回一個布爾值,表示一個元素是否可選擇。
driver.findElement(By.xpath("http://select[@name='jump']/option[1]"))
.isSelected()
getSize():返回一個網(wǎng)頁元素的寬度和高度。
var dimensions=driver.findElement(By.locatorType("path"))
.getSize();
dimensions.width;
dimensions.height;
getLocation():返回網(wǎng)頁元素左上角的x坐標(biāo)和y坐標(biāo)。
var point = driver.findElement(By.locatorType("path")).getLocation();
point.x; // 等同于 point.getX();
point.y; // 等同于 point.getY();
getCssValue():返回網(wǎng)頁元素指定的CSS屬性的值。
driver.get("https://www.google.com");
var element = driver.findElement(By.xpath("http://div[@id='hplogo']"));
console.log(element.getCssValue("font-size"));
console.log(element.getCssValue("font-weight"));
console.log(element.getCssValue("color"));
console.log(element.getCssValue("background-size"));
以下方法用來跳轉(zhuǎn)到某一個頁面。
get():要求瀏覽器跳到某個網(wǎng)址。
driver.get("URL");
navigate().back():瀏覽器回退。
driver.navigate().back();
navigate().forward():瀏覽器前進。
driver.navigate().forward();
navigate().to():跳轉(zhuǎn)到瀏覽器歷史中的某個頁面。
driver.navigate().to("URL");
navigate().refresh():刷新當(dāng)前頁面。
driver.navigate().refresh();
// 等同于
driver.navigate()
.to(driver.getCurrentUrl());
// 等同于
driver.findElement(By.locatorType("path"))
.sendKeys(Keys.F5);
getCookies():獲取cookie
driver.get("https://www.google.com");
driver.manage().getCookies();
getCookieNamed() :返回指定名稱的cookie。
driver.get("https://www.google.com");
console.log(driver.manage().getCookieNamed("NID"));
addCookie():將cookie加入當(dāng)前頁面。
driver.get("https://www.google.com");
driver.manage().addCookie(cookie0);
deleteCookie():刪除指定的cookie。
driver.get("https://www.google.co.in");
driver.manage().deleteCookieNamed("NID");
maximize():最大化瀏覽器窗口。
var driver = new FirefoxDriver();
driver.manage().window().maximize();
getSize():返回瀏覽器窗口、圖像、網(wǎng)頁元素的寬和高。
driver.manage().window().getSize();
getPosition():返回瀏覽器窗口左上角的x坐標(biāo)和y坐標(biāo)。
console.log("Position X: " + driver.manage().window().getPosition().x);
console.log("Position Y: " + driver.manage().window().getPosition().y);
console.log("Position X: " + driver.manage().window().getPosition().getX());
console.log("Position Y: " + driver.manage().window().getPosition().getY());
setSize():定制瀏覽器窗口的大小。
var d = new Dimension(320, 480);
driver.manage().window().setSize(d);
driver.manage().window().setSize(new Dimension(320, 480));
setPosition():移動瀏覽器左上角到指定位置。
var p = new Point(200, 200);
driver.manage().window().setPosition(p);
driver.manage().window().setPosition(new Point(300, 150));
getWindowHandle():返回當(dāng)前瀏覽器窗口。
var parentwindow = driver.getWindowHandle();
driver.switchTo().window(parentwindow);
getWindowHandles():返回所有瀏覽器窗口。
var childwindows = driver.getWindowHandles();
driver.switchTo().window(childwindow);
switchTo.window():在瀏覽器窗口之間切換。
driver.SwitchTo().Window(childwindow);
driver.close();
driver.SwitchTo().Window(parentWindow);
以下方法處理瀏覽器的彈出窗口。
dismiss() :關(guān)閉彈出窗口。
var alert = driver.switchTo().alert();
alert.dismiss();
accept():接受彈出窗口,相當(dāng)于按下接受OK按鈕。
var alert = driver.switchTo().alert();
alert.accept();
getText():返回彈出窗口的文本值。
var alert = driver.switchTo().alert();
alert.getText();
sendKeys():向彈出窗口發(fā)送文本字符串。
var alert = driver.switchTo().alert();
alert.sendKeys("Text to be passed");
authenticateUsing():處理HTTP認(rèn)證。
var user = new UserAndPassword("USERNAME", "PASSWORD");
alert.authenticateUsing(user);
以下方法模擬鼠標(biāo)和鍵盤的動作。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: