3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Web3.0検証(21)-MeteorでTODO管理アプリの開発(リグレッションテスト)

Last updated at Posted at 2022-06-03
[前回] Web3.0検証(20)-MeteorでTODO管理アプリの開発(publish/subscribeによるデータ制御)

はじめに

今回は、アプリのリグレッションテスト機能です。

リグレッションテストの機能追加

  • テスト機能を追加し、リグレッション発生せず、期待どおり機能することを確認
  • リグレッションテスト(Regression Test)とは
    • プログラムの変更に伴い、システムに予想外の影響が現れていないかを確認するテスト
    • リグレッションは、回帰テスト退行テストとも呼ばれる
  • メソッドの1つを実行し、正しく機能するか確認するテストを作成

アプリをテストモードで実行

  • 依存関係をインストール

    • MochaJavaScriptテストフレームワークのテストドライバーを追加
        $ meteor add meteortesting:mocha
    
    • テストアサーションライブラリをインストール
        $ meteor npm install --save-dev chai
    
  • アプリをテストモードで実行

    • テストドライバーパッケージを指定し、meteor testを実行
    • ポート番号が衝突しないように
      • 通常アプリの実行を停止するか
      • –port XYZで代替ポートを指定
$ cd simple-todos-react
$ TEST_WATCH=1 meteor test --driver-package meteortesting:mocha
[[[[[ Tests ]]]]]

=> Started proxy.
=> Started HMR server.
=> Started MongoDB.
I20220603-21:31:00.827(9)?
I20220603-21:31:00.840(9)? --------------------------------
I20220603-21:31:00.841(9)? ----- RUNNING SERVER TESTS -----
I20220603-21:31:00.841(9)? --------------------------------
I20220603-21:31:00.841(9)?
I20220603-21:31:00.842(9)?
I20220603-21:31:00.842(9)?
I20220603-21:31:00.842(9)?   simple-todos-react
=> Started your app.

=> App running at: http://localhost:3000/
I20220603-21:31:00.845(9)?     ✓ package.json has correct name
I20220603-21:31:00.845(9)?     ✓ server is not client
I20220603-21:31:00.846(9)?
I20220603-21:31:00.846(9)?
I20220603-21:31:00.846(9)?   2 passing (8ms)
I20220603-21:31:00.847(9)?
I20220603-21:31:00.847(9)? Load the app in a browser to run client tests, or set the TEST_BROWSER_DRIVER environment variable. See https://github.com/meteortesting/meteor-mocha/blob/master/README.md#run-app-tests

サーバーテストは成功しました。

  • ブラウザでクライアントテスト

http://localhost:3000/にアクセス。

image.png

クライアントテストも成功しました。

  • 上述テストが可能な理由
    • Meteorアプリケーションには、サンプルテストを含むtests/main.jsモジュールが含まれている
    • Mochaなどのテストフレームワークでサポートするdescribeitassertスタイルを使用できる

スキャフォールド(Scaffold)テスト

  • テストを複数モジュールに分割可能
  • 以下の新しいテストモジュールを追加
imports/api/tasksMethods.tests.js
import { Meteor } from 'meteor/meteor';

if (Meteor.isServer) {
  describe('Tasks', () => {
    describe('methods', () => {
      it('can delete owned task', () => {});
    });
  });
}
  • tests/main.jsにインポート
  • これ以外のテストは不要で残りコードをすべて削除
tests/main.js
import '/imports/api/tasksMethods.tests.js';

データベースをテスト

  • データベースが期待どおりの状態にあることを確認
    • MochabeforeEachコンストラクトを使用
  • テスト実行ごとに異なるランダムなuserIdに関連付けられた、単一タスクを作成
imports/api/tasksMethods.tests.js
import { Meteor } from 'meteor/meteor';
import { Random } from 'meteor/random';
import { TasksCollection } from '/imports/db/TasksCollection';

if (Meteor.isServer) {
  describe('Tasks', () => {
    describe('methods', () => {
      const userId = Random.id();
      let taskId;

      beforeEach(() => {
        TasksCollection.remove({});
        taskId = TasksCollection.insert({
          text: 'Test Task',
          createdAt: new Date(),
          userId,
        });
      });
    });
  });
}

タスク削除をテスト

  • 認証されたユーザーでtasks.removeメソッドを呼び出すテストを記述
    • タスクが削除されたことを確認
  • メソッドを簡単に呼び出すため、ユーティリティパッケージをインストール
$ meteor add quave:testing
  • アサーションツールchaiから、assertをインポート
imports/api/tasks.tests.js
import { Meteor } from 'meteor/meteor';
import { Random } from 'meteor/random';
import { mockMethodCall } from 'meteor/quave:testing';
import { assert } from 'chai';
import { TasksCollection } from '/imports/db/TasksCollection';
import '/imports/api/tasksMethods';

if (Meteor.isServer) {
  describe('Tasks', () => {
    describe('methods', () => {
      const userId = Random.id();
      let taskId;

      beforeEach(() => {
        TasksCollection.remove({});
        taskId = TasksCollection.insert({
          text: 'Test Task',
          createdAt: new Date(),
          userId,
        });
      });

      it('can delete owned task', () => {
        mockMethodCall('tasks.remove', taskId, { context: { userId } });

        assert.equal(TasksCollection.find().count(), 0);
      });
    });
  });
}

その他テスト

  • 必要なテストを追加
imports/api/tasks.tests.js
import { Meteor } from 'meteor/meteor';
import { Random } from 'meteor/random';
import { mockMethodCall } from 'meteor/quave:testing';
import { assert } from 'chai';
import { TasksCollection } from '/imports/db/TasksCollection';
import '/imports/api/tasksMethods';

if (Meteor.isServer) {
  describe('Tasks', () => {
    describe('methods', () => {
      const userId = Random.id();
      let taskId;

      beforeEach(() => {
        TasksCollection.remove({});
        taskId = TasksCollection.insert({
          text: 'Test Task',
          createdAt: new Date(),
          userId,
        });
      });

      it('can delete owned task', () => {
        mockMethodCall('tasks.remove', taskId, { context: { userId } });

        assert.equal(TasksCollection.find().count(), 0);
      });

      it(`can't delete task without an user authenticated`, () => {
        const fn = () => mockMethodCall('tasks.remove', taskId);
        assert.throw(fn, /Not authorized/);
        assert.equal(TasksCollection.find().count(), 1);
      });

      it(`can't delete task from another owner`, () => {
        const fn = () =>
          mockMethodCall('tasks.remove', taskId, {
            context: { userId: 'somebody-else-id' },
          });
        assert.throw(fn, /Access denied/);
        assert.equal(TasksCollection.find().count(), 1);
      });

      it('can change the status of a task', () => {
        const originalTask = TasksCollection.findOne(taskId);
        mockMethodCall('tasks.setIsChecked', taskId, !originalTask.isChecked, {
          context: { userId },
        });

        const updatedTask = TasksCollection.findOne(taskId);
        assert.notEqual(updatedTask.isChecked, originalTask.isChecked);
      });

      it('can insert new tasks', () => {
        const text = 'New Task';
        mockMethodCall('tasks.insert', text, {
          context: { userId },
        });

        const tasks = TasksCollection.find({}).fetch();
        assert.equal(tasks.length, 2);
        assert.isTrue(tasks.some(task => task.text === text));
      });
    });
  });
}
  • package.jsonファイルのscriptsセクションに省略形を追加

    • テストコマンドを簡単に入力できるようになる
    • Meteorアプリに付属された、事前構成済みnpmスクリプトを使用/変更
  • サーバー側のテストのみ実行したい

    • 標準のmeteor npm testコマンドを用いる、次のコマンドと等価
    • $ meteor test --once --driver-package meteortesting:mocha
    • すべてのテストに合格したら0で終了
    • Travis CICircleCIなど、CI(継続的インテグレーション)環境での実行に適している
  • アプリケーションの開発中にテストを実行したい

  • または、開発サーバーが再起動するたびにテストを再実行したい

    • meteor npm run test-appを使用、次のコマンドと等価
    • TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha
      • --full-appを追加することで、アプリケーションコードも読み込まれる
  • ブラウザからアプリを確認

    • ログイン
      • ユーザー名: meteorite
      • パスワード: password

クライアントテストとサーバーテストの両方を実行しながら、
ブラウザーでアプリを操作できるようになりました。

おわりに

アプリのリグレッションテスト機能を実装しました。
次回も続きます。お楽しみに。

[次回] Web3.0検証(22(最終回))-MeteorでTODO管理アプリの開発(デプロイ&公開)
3
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?