Testing Sencha Apps by Mats Bryntse (Sencha Touch North West Meetup)
という動画を見てSiestaに興味を持ったので、さわり始めてみました。
この画面は、この記事の最後のテスト、GridPanelのテストを実行したときの画面です。画面上でテストを選択して実行させる。ビジュアルコンポーネントのテストでは、その表示も確認できます。冒頭のビデオを見ていても、とてもワクワクするような作りになっています。
Siestaの配置
Siestaのexampleに従って次のようにしました。
▾ public_html/
▾ ex_siesta/
▸ app/
▸ data/
▸ resources/
▸ siesta/ <-- SiestaのSDK
▸ tests/
test_harness.html
test_harness.js
app.js
index.html
▸ extjs/ <-- Ext JS のSDK
テストの起点となるのは、test_harness.html と test_harness.js です。
test_harness.html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="../../extjs/resources/css/ext-all.css"/>
<link rel="stylesheet" type="text/css" href="siesta/resources/css/siesta-all.css">
<script type="text/javascript" src="../../extjs/ext-all.js"></script>
<script type="text/javascript" src="siesta/siesta-all.js"></script>
<script type="text/javascript" src="test_harness.js"></script>
</head>
<body>
</body>
</html>
CSSとJS、それぞれExt JSとSiestaのものを読み込みます。
最後に、test_harness.js
を読み込みます。
Harness
test_harness.js
var Harness = Siesta.Harness.Browser.ExtJS;
Harness.configure({
title : 'MVC Test Suite',
loaderPath : { 'EX' : 'app' },
preload : [
"../extjs/resources/css/ext-all.css",
"../extjs/ext-all-debug.js"
]
});
Harness.start({
group: 'Sanity',
items: [
'tests/010_sanity.t.js'
]
},{
group: 'Model',
items: [
'tests/021_employee.t.js',
'tests/022_depertment.t.js'
]
},{
group: 'View',
items: [
'tests/031_list.t.js',
'tests/032_grid.t.js'
]
});
Harnessの設定
-
loaderPath
loaderPathには、アプリケーションの名前空間へのパスをセットします。
(Ext.loaderに設定するのと同じですね) -
preload
preloadには各テストをロードする前にロードすべきファイルを指定します。
テストコード
実際のテストは、この場合testsディレクトリの下に置きます。
それぞれのテストは、完全に独立して実行されグローバルスコープもクリーンナップされます。
tests/010_sanity.t.js
StartTest(function(t) {
t.diag("Sanity test, loading classes on demand and verifying they were indeed loaded.");
t.ok(Ext, 'ExtJS is here');
t.requireOk('EX.controller.Main');
});
StartTestという関数の引数に無名関数を渡しています。
テストコードは
StartTest(function (t) { .... })
でラップします。
StartTestに渡す関数に第1引数として渡される引数(前記のt
)は、Siesta.Testのインスタンスです。
で、Siesta.Test のインスタンスにはいくつかのアサーションメソッドがあります。
それを使ってテストを書いて行きます。ここで使っているのは次のようなものです。
-
ok
メソッド
値が真になる場合にテストをパスします -
requireOk
メソッド
Siesta.Test.ExtJSクラスのメソッド。Ext.require()で指定したクラスをロードして、コールバック関数が指定されていたら、それを実行する。 -
done
メソッド
ここでは使ってませんが、テストを終了するメソッドです。
Modelのテスト
StartTest(function(t) {
t.requireOk('EX.model.Employee', function() {
var mod = Ext.create('EX.model.Employee', {
name: '鬼瓦 権三',
department_id: 1,
email: 'gonzo@onigawara.com',
gender: '男',
age: 33
});
t.is(mod.genderEn(), 'male', 'genderEn works ok');
t.is(mod.get('email'), 'gonzo@onigawara.com', 'Could read email');
});
});
-
is
メソッド
1つ目と2つ目の引数が等しければテストをパスします
genderEnというメソッドは、Modelで定義しているメソッドで
genderEn: function(value) {
var me = this,
gender = me.get('gender');
if(gender == '男'){
return 'male';
} else if(gender == '女'){
return 'female';
} else {
return gender;
}
}
こんな感じのメソッドです。このテストでは、isメソッドでその動作を確認しているのと、
普通にgetメソッドでemailを読み出して、値を比較してみています。
Storeのテスト
StartTest(function(t) {
t.requireOk('EX.store.Departments', function() {
var s = Ext.create('EX.store.Departments'),
async = t.beginAsync();
s.load({
callback: function() {
var c, m;
t.pass('loaded');
c = s.getCount();
t.isGreater(c, 0, Ext.String.format('レコードが{0}件', c));
m = s.getAt(0);
t.ok(m, Ext.String.format('最初のレコードのname:{0}', m.get('name')));
t.endAsync(async);
}
});
});
});
ストアのテストでは、ストアをloadしたコールバックでテストを実行しました。
非同期のコールバックを使ったテストをする場合は、beginAsync/ednAsyncを使って、その非同期呼び出しが完了するまで、
テストが終了しないようにする必要があります。
View のテスト
Gridをテストしてみます。
StartTest(function(t) {
t.requireOk(
[
'EX.model.Employee',
'EX.store.Employees',
'EX.model.Department',
'EX.store.Departments',
'EX.view.Grid'
],
function() {
var grid;
Ext.create('EX.store.Employees',{
storeId: 'Employees'
});
Ext.create('EX.store.Departments', {
storeId: 'Departments'
});
grid = Ext.create('EX.view.Grid',{
renderTo: Ext.getBody()
});
t.waitForRowsVisible(grid, function() {
t.is(grid.store.getCount(), grid.getView().getNodes().length, 'Rendered all data in store ok');
t.matchGridCellContent(grid, 0, 1, grid.store.first().get('name'), 'Found full name in first cell');
});
}
);
});
テストできるようになるまで、ちょっとハマりました。
上記で、ストアを生成する時に、storeIdを指定しています。テスト対象のストアにはstoreIdの定義はありません。
通常、Gridではstoreコンフィグに文字列でストアを指定しますね。
Ext.define('EX.view.Grid', {
store: 'Users'
:
:
});
こんな感じですよね。ここで指定している 'Users' っていうのは、ストアのstoreIdになります。
MVCではstoreIdをつけていなくても、クラス名からstoreIdを生成してストアをStoreManagerに登録してくれますが、
テストの状態ではそんなことはありません。
ですので、ストアをインスタンス化するときにstoreIdを指定してやる必要があります。
で、グリッドを生成してやると、Siestaの画面にちゃんとGridが表示されます。
t.waitForRowsVisible を使ったテストは、Siestaのサンプルの中にあったものです。
こういったExt JSのテストに特化したメソッドが用意されているのはいいですね。