面向模型編程;css
測試驅動開發;html
先保障交互邏輯,再調整細節。---by 雪狼。angularjs
爲何要自動化測試?web
1,提升產出質量。編程
2,減小重構時的痛。反正我最近重構多了,痛苦經歷多了。app
3,便於新人接手。函數
angular自動化測試主要分:端到端測試和單元測試,很明顯二者都要熟練掌握。單元測試
端到端測試是從用戶的角度出發,認爲整個系統是個黑盒,只會有UI暴露給用戶,主要是模仿人工操做測試。測試
單元測試認爲整個系統是白盒,能夠用來測試服務,控制器,過濾器還有基礎函數等。動畫
端到端測試使用protractor,今天就扯這個。
爲何使用Protractor,也就是說Protractor有什麼好處,有沒有替代品?
1,不須要基於id,css選擇器,xpath等查詢元素,你能夠基於綁定,模型,迭代器等等進行測試。
2,避免回調地獄。對比下面的代碼就知道了。
//沒有protractor driver.getTitle().then(function(title){ expect(title).toBe('Baidu'); }); //使用protractor expect(browser.getTitle()).toEqual('Baidu');
替代品:capybara-angular等。
前戲作完了,開始辦正事吧。
describe('hello world', function() { it('標題是hello world', function() { browser.get('測試地址本身搞一個咯'); expect(browser.getTitle()).toEqual('hello world'); }); });
說白了就是但願指定的連接的標題是"hello world"
首先咱們必須跳轉到指定的頁面,跳轉頁面有兩種方法。
1,browser.get,跳轉到指定的頁面,還會從新刷新整個頁面。
2,browser.setLocation,更確切的說,是跳轉路由,修改#後面部分。
「等待某個元素出現」而不是「等待頁面加載完畢」,若是頁面加載完畢以後,立刻去獲取某個元素,極可能改元素不存在,而後直接報錯退出。
點擊某個按鈕以後,彈窗,彈窗有漸進動畫,具體彈窗內的元素何時出現不肯定,那麼必須「等待某個元素出現」。怎麼實現?
//等待ng-model="password"的出現,最多等待20秒 browser.wait(function(){ return browser.isElementPresent(by.model("password")); },20000);
封裝頁面對象,英文叫PageObject,我也不知道怎麼翻譯,說白了就是封裝組件或者頁面的選擇器。
爲何要有這一步?
先看一段代碼:
describe('angularjs homepage', function() { it('should greet the named user', function() { browser.get('http://www.angularjs.org'); element(by.model('yourName')).sendKeys('Julie'); var greeting = element(by.binding('yourName')); expect(greeting.getText()).toEqual('Hello Julie!'); }); describe('todo list', function() { var todoList; beforeEach(function() { browser.get('http://www.angularjs.org'); todoList = element.all(by.repeater('todo in todos')); }); it('should list todos', function() { expect(todoList.count()).toEqual(2); expect(todoList.get(1).getText()).toEqual('build an angular app'); }); it('should add a todo', function() { var addTodo = element(by.model('todoText')); var addButton = element(by.css('[value="add"]')); addTodo.sendKeys('write a protractor test'); addButton.click(); expect(todoList.count()).toEqual(3); expect(todoList.get(2).getText()).toEqual('write a protractor test'); });
這是沒封裝的狀況。
1,語義化不好,根本很難看明白在作神馬。
2,重複代碼多。browser.get('http://www.angularjs.org');就不止出現了一次。
3,耦合嚴重。若是標籤結構改動,代碼不少地方都要改。
4,難以維護,隨着項目的增加和時間的推移,沒有人會樂意在這上面添加其它測試功能。
問題已經暴露出來了,怎麼封裝?
封裝以前,建議過一遍官方的教程和API接口,經常使用的很少,難度不大。傳送門。
舉個栗子,很簡單的。如今有個滾動條。示意圖有點醜,別笑。
封裝出來應該以下,這樣即便滾動條的代碼結構改了什麼的,只要改下面的代碼,而具體測試邏輯不用動。
function ScrollBarSelector(model){ Object.defineProperty(this,"target",{ get:function(){ return typeof model == "string" ? element(by.model(model)) : model; } }) Object.defineProperty(this,"pre",{ get:function(){ return this.target.$(".pre"); } }) Object.defineProperty(this,"next",{ get:function(){ return this.target.$(".next"); } }) Object.defineProperty(this,"scrollButton",{ get:function(){ return this.target.$(".scrollButton"); } }) Object.defineProperty(this,"value",{ get:function(){ return this.target.$("input").getAttribute("value"); } }) }
測試邏輯,基本上就是,
點擊某個按鈕:scrollBar.next.click()
但願某個輸入框的內容爲:expect(scrollBar.value).toBe("xx");
最後,仍是附上登陸的測試和路由跳轉,google上面不少人都在問。不少人問的問題是,登陸完了,跳轉頁面,怎麼知道頁面跳轉了。
spec.js
!function(){ require(".LoginAction.js"); require(".LogoutAction.js"); require(".ScrollbarAction.js"); describe("自動登陸",function(){ new LoginAction().execute("GetLiShu","123456"); }) describe('testScrollbar', function () { new ScrollbarAction().execute(); }); describe("退出登陸",function(){ new LogoutAction().execute(); }); }();
LoginAction.js
!function(){ function LoginAction(){ } var prop = LoginAction.prototype; prop.execute = function(userName,password){ beforeEach(function () { //先跳轉到登陸頁面 browser.get("登陸頁面"); //等待輸入框出來 browser.wait(function(){ return browser.isElementPresent(by.model("username")); },20000); }) //輸入帳號密碼而後點擊登陸 it('自動登陸', function () { element(by.model("username")).sendKeys(userName); element(by.model("password")).sendKeys(password); element(by.css(".login-input-btn")).click(); }); } module.exports = LoginAction; }();
ScrollbarAction.js
!function(){ beforeEach(function () { browser.setLocation("/app/common/stepper"); }) it('測試滾動條', function () { var scrollbar = new ScrollbarSelector("vm.scroll"); //等待滾動條出來,最多等待20秒,滾動條出來了,立刻處理測試代碼 browser.wait(function(){ return browser.isElementPresent(numberDefault.mius); },20000); //這裏省略不少行測試代碼 }); }();