backbone.jsにjasmineでテストコード書いてみた (lt資料)
DESCRIPTION
BACKBONE.JSのModelに対して JasmineとSinon.jsでテストを記述してみました。 間違いとかもっとこうした方が良いとかございましたら @itokami1123まで教えてください! 2013/10/16(水) JSテスト勉強会@福岡 第1回 LT資料 ---------------------------------------------------------------- Web制作向け無料写真素材/ぱくたそ (http://www.pakutaso.com)の写真を使用しました。 ありがとうございます。TRANSCRIPT
BACKBONE.JSにJasmineでテストコード書いてみた
2013/10/16(水) JSテスト勉強会@福岡 第1回 LT資料
写真はWeb制作向け無料写真素材/ぱくたそ http://www.pakutaso.comを使ってます。ありがとうございます。
+ Sinon.JS
13年10月16日水曜日
自己紹介です========
- twitter: @itokami1123- 下請けやら派遣やらなんやら開発してます- JavaEE6と会計の勉強はじめました。- 目標 業務系Webアプリの世界にもJavaScriptMVCを! コミュニティの力で福岡を一つにして 景気をよくする!(一生福岡でPGしたいっす)
13年10月16日水曜日
今日の資料おかしいと思ったら途中でビシバシ(優しく)突っ込んでね!
13年10月16日水曜日
BACKBONE.JSで書いているとソースが Model View に分かれます!
13年10月16日水曜日
と言う事は時間がなくても Modelだけテストコードかけるかも!?
13年10月16日水曜日
↑のような画面を作ってるときの...
13年10月16日水曜日
↑の一行明細のModelデータをテスト!
13年10月16日水曜日
メニュー表項目(1行分データ)Modelにvar MenuItem = Backbone.Model.extend({
defaults: function(){
return { name: "", price: 0 , selected: false };
},
toggleSelected: function(){
var putData={"selected": !this.get("selected")}; this.save( putData, {wait: true});
}
});
13年10月16日水曜日
オブジェクト生成のテスト!
var MenuItem = Backbone.Model.extend({
defaults: function(){
return { name: "", price: 0 , selected: false };
},
toggleSelected: function(){
var putData={"selected": !this.get("selected")}; this.save( putData);
}
});
describe ("MenuItem", function() { var menuItem;
beforeEach(function() { menuItem = new MenuItem(); });
afterEach(function() { menuItem.destroy(); menuItem = null; });
describe( "オブジェクト生成時", function() { it( "初期値としてデフォルト値が設定される事", function() { expect(menuItem).toBeDefined(); expect(menuItem.get("name")).toBe(""); expect(menuItem.get("price")).toBe(0); expect(menuItem.get("selected")).toBe(false); }); });
});
13年10月16日水曜日
オブジェクト生成時テストはグリーン!やったね!
var MenuItem = Backbone.Model.extend({
defaults: function(){
return { name: "", price: 0 , selected: false };
},
toggleSelected: function(){
var putData={"selected": !this.get("selected")}; this.save( putData);
}
});
describe ("MenuItem", function() { var menuItem;
beforeEach(function() { menuItem = new MenuItem(); });
afterEach(function() { menuItem.destroy(); menuItem = null; });
describe( "オブジェクト生成時", function() { it( "初期値としてデフォルト値が設定される事", function() { expect(menuItem).toBeDefined(); expect(menuItem.get("name")).toBe(""); expect(menuItem.get("price")).toBe(0); expect(menuItem.get("selected")).toBe(false); }); });
});
13年10月16日水曜日
var MenuItem = Backbone.Model.extend({ ・・・省略・・・ toggleSelected: function(){ var putData={ "selected": !this.get("selected") }; this.save( putData, {wait: true}); }});
次はメニューボタンのON/OFFの切り替えテスト!
describe ("MenuItem", function() { var menuItem; beforeEach(function() { menuItem = new MenuItem(); }); afterEach(function() { menuItem.destroy(); menuItem = null; });
describe( "メニュー選択時", function(){ it( "トグル選択される事", function(){ expect(menuItem).toBeDefined(); expect(menuItem.get("selected")).toBeFalsy(); menuItem.toggleSelected(); expect(menuItem.get("selected")).toBeTrusy(); }); });
});
13年10月16日水曜日
var MenuItem = Backbone.Model.extend({ ・・・省略・・・ toggleSelected: function(){ var putData={ "selected": !this.get("selected") }; this.save( putData, {wait: true}); }});
ぐぁぁぁぁぁ...、Σ( ` o ‘
describe ("MenuItem", function() { var menuItem; beforeEach(function() { menuItem = new MenuItem(); }); afterEach(function() { menuItem.destroy(); menuItem = null; });
describe( "メニュー選択時", function(){ it( "トグル選択される事", function(){ expect(menuItem).toBeDefined(); expect(menuItem.get("selected")).toBeFalsy(); menuItem.toggleSelected(); expect(menuItem.get("selected")).toBeTrusy(); }); });
});
13年10月16日水曜日
var MenuItem = Backbone.Model.extend({ ・・・省略・・・ toggleSelected: function(){ var putData={ "selected": !this.get("selected") }; this.save( putData, {wait: true}); }});
な、なんで...Σ( ` o ‘
describe ("MenuItem", function() { var menuItem; beforeEach(function() { menuItem = new MenuItem(); }); afterEach(function() { menuItem.destroy(); menuItem = null; });
describe( "メニュー選択時", function(){ it( "トグル選択される事", function(){ expect(menuItem).toBeDefined(); expect(menuItem.get("selected")).toBeFalsy(); menuItem.toggleSelected(); expect(menuItem.get("selected")).toBeTrusy(); }); });
});
サーバにPUT更新するリクエストを単体で動作させる必要がある作りでした...
13年10月16日水曜日
そこでSinon.JS使います!
http://sinonjs.org/13年10月16日水曜日
var MenuItem = Backbone.Model.extend({ ・・・省略・・・ toggleSelected: function(){ var putData={
"selected": !this.get("selected")};
this.save( putData, {wait: true}); }});
describe ("MenuItem", function() { describe( "メニュー選択時", function(){ var menuItem,server; beforeEach( function(){ menuItem = new MenuItem({ "id": 1, "name": "test", "price": 100, "selected": false }); menuItem.url = "/unitTestUrl"; server = sinon.fakeServer.create(); }); afterEach(function () { server.restore(); }); it( "トグル選択される事", function(){ expect(menuItem).toBeDefined(); expect(menuItem.get("selected")).toBeFalsy(); server.respondWith( "PUT","/unitTestUrl",[ 200, {"Content-Type": "application/json"}, '{"id":1,"name":"test","price":100,"selected":true}' ]); menuItem.toggleSelected(); server.respond(); expect(menuItem.get("selected")).toBeTruthy(); }); });});
Sinon.jsの機能でダミーの応答を返す!
テストコードを書き直しました〜。
ダミーで返す値を細かく指定できます!
13年10月16日水曜日
次は↑の明細複数行のModelデータをテスト!
13年10月16日水曜日
var MenuList = Backbone.Collection.extend({
model: MenuItem,
comparator: 'id'
sumPrice: function(){ var sum = 0, selectedMenuItems = this.where({ selected:true }); _.each( selectedMenuItems, function( model){ sum += model.get( "price"); }); return sum; },
createMenu: function(name,price){ var menuItemData = { name:name, price:price, selected:false }; this.create(menuItemData, {wait: true}); },
});
明細複数行Model(Collection)に
13年10月16日水曜日
var MenuList = Backbone.Collection.extend({
model: MenuItem,
comparator: 'id'
sumPrice: function(){ var sum = 0, selectedMenuItems = this.where({ selected:true }); _.each( selectedMenuItems, function( model){ sum += model.get( "price"); }); return sum; },
createMenu: function(name,price){ var menuItemData = { name:name, price:price, selected:false }; this.create(menuItemData, {wait: true}); },
});
合計金額算出のテストケース追加!
describe ( "MenuList", function() {
describe ( "選択メニュー合計金額算出", function() { it( "格納モデルの選択中より合計金額を算出する", function() {
var menuList = new MenuList([ { name:"a", price: 100, selected: true}, { name:"b", price: 200, selected: false},
{ name:"c", price: 400, selected: true}, ]); expect( menuList.sumPrice()).toBe( 500);
}); });
});
13年10月16日水曜日
var MenuList = Backbone.Collection.extend({
model: MenuItem,
comparator: 'id'
sumPrice: function(){ var sum = 0, selectedMenuItems = this.where({ selected:true }); _.each( selectedMenuItems, function( model){ sum += model.get( "price"); }); return sum; },
createMenu: function(name,price){ var menuItemData = { name:name, price:price, selected:false }; this.create(menuItemData, {wait: true}); },
});
合計金額算出のテストはOK(グリーン)!\(^o^)/
describe ( "MenuList", function() {
describe ( "選択メニュー合計金額算出", function() { it( "格納モデルの選択中より合計金額を算出する", function() {
var menuList = new MenuList([ { name:"a", price: 100, selected: true}, { name:"b", price: 200, selected: false},
{ name:"c", price: 400, selected: true}, ]); expect( menuList.sumPrice()).toBe( 500);
}); });
});
13年10月16日水曜日
var MenuList = Backbone.Collection.extend({
model: MenuItem,
comparator: 'id'
sumPrice: function(){ var sum = 0, selectedMenuItems = this.where({ selected:true }); _.each( selectedMenuItems, function( model){ sum += model.get( "price"); }); return sum; },
createMenu: function(name,price){ var menuItemData = { name:name, price:price, selected:false };
this.create(menuItemData, {wait: true});
},
});
次は新規メニュー登録のテストケース追加!
describe ( "MenuList", function() {// ・・・省略・・・
describe( "新規メニュー表登録", function() { it( "サーバより返却された名称と金額が設定されること", function(){ server = sinon.fakeServer.create(); var menuList = new MenuList(); menuList.url = "/unitTestUrl"; server.respondWith([ 200, {"Content-Type": "application/json"}, '{"id":123,"name":"sevNam",
"price":1005,"selected":false}' ]); menuList.createMenu( 'test', 1000); server.respond();
expect( menuList.size()).toBe( 1);
var model = menuList.get(123); expect( model.get("name") ).toBe( "sevNam"); expect( model.get("price") ).toBe( 1005);
}) });});
13年10月16日水曜日
var MenuList = Backbone.Collection.extend({
model: MenuItem,
comparator: 'id'
sumPrice: function(){ var sum = 0, selectedMenuItems = this.where({ selected:true }); _.each( selectedMenuItems, function( model){ sum += model.get( "price"); }); return sum; },
createMenu: function(name,price){ var menuItemData = { name:name, price:price, selected:false };
this.create(menuItemData, {wait: true});
},
});
新規メニュー表登録処理もOK(グリーン)!
describe ( "MenuList", function() {// ・・・省略・・・
describe( "新規メニュー表登録", function() { it( "サーバより返却された名称と金額が設定されること", function(){ server = sinon.fakeServer.create(); var menuList = new MenuList(); menuList.url = "/unitTestUrl"; server.respondWith([ 200, {"Content-Type": "application/json"}, '{"id":123,"name":"sevNam",
"price":1005,"selected":false}' ]); menuList.createMenu( 'test', 1000); server.respond();
expect( menuList.size()).toBe( 1);
var model = menuList.get(123); expect( model.get("name") ).toBe( "sevNam"); expect( model.get("price") ).toBe( 1005);
}) });});
13年10月16日水曜日
まとめ
13年10月16日水曜日
まとめ
まとめです========
- Backbone.jsのように MV*にすれば Modelのみのテストコードが書きやすい!
- ModelからのAjax通信も Sinon.jsのFakeServerを使えば ユニットテストできる!
13年10月16日水曜日
何か質問とかもっとこうした方が良いよとかありますか??
13年10月16日水曜日
ご清聴ありがとうございました!
今日の資料で出てきたソースは以下で公開してます。https://github.com/itokami1123dev/hamburger_shop_prj
13年10月16日水曜日