LoginSignup
3
3

More than 5 years have passed since last update.

SestaでMVCアプリのテストを書く

Posted at

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 : [
       &quot;../extjs/resources/css/ext-all.css&quot;,
       &quot;../extjs/ext-all-debug.js&quot;
    ]

});

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(&quot;Sanity test, loading classes on demand and verifying they were indeed loaded.&quot;);

    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のテストに特化したメソッドが用意されているのはいいですね。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3