waveさんの技術日誌

wave1008の日記の新館です。

スマホアプリ用自動テストツール Shirates のREADME

この記事は

github.com

のREADMEの日本語訳です。

 

Shirates(shirates-core)

Shiratesはモバイルアプリのテストコードを書くのを簡単かつ楽しいものにする結合テストフレームワークです。

shirates-coreはコアライブラリです。

 

3行で機能を説明

  1. テストコードを記述するためのほぼクロスプラットフォームAPIを提供します。AndroidiOSのプラットフォームをサポートします
  2. 強力なログ出力機能とレポーティング機能を提供します
  3. テスト環境をセットアップするための柔軟な構成管理フレームワークを提供します

もう少し詳しく説明

  • 画面の要素を操作したりそれらのステータスを検証したりするための使いやすいAPIを提供します
  • 内部的にはAppiumを使用しており、AndroidiOSアプリをサポートします。画面要素のマッピングファイルを使用することでAndroidiOSのテストコードを統合することができます
  • テストのセッションが完了した時にログ、スクリーンショット、HTMLレポート、MS-Excelワークシートを自動的に出力します
  • MS-Excelワークシートでテスト結果を確認し、追加のテストを手動で実行し、ワークシートに追記することができます
  • テストを実際に実行することなくテスト仕様書(Spec-Report)を生成することができます。Spec-Reportは手動テストやレビューで便利です。テスト対象のアプリがまだ開発中であってもテストコードを書き、手動テストのためにSpec-Reportを出力することができます

 

Shiratesという名称の由来

  • オリジナルのテストフレームワークがSHIRATAMA Test Frameworkという名称でした。そのオープンソースバージョンをShiratesと呼んでいます
  • SHIRATAMAとは和菓子の白玉団子に由来しており、テスト結果のOKの"O"が白玉団子に見えたのでそう名付けました

 

テストコード開発環境

  • OS: macOS または Windows (iOSアプリの開発にはmacOSが必要です)
  • IDE: IntelliJ IDEA (Ultimate版またはCommunity版)
  • プログラム言語: Kotlin

 

ニックネーム指向の自動テスト

ニックネームはShiratesのキーコンセプトの一つであり、テストコードを読みやすく理解しやすいものにします。画面、画面要素、アプリ、テストデータなどに対してニックネームファイルを作成してニックネームを定義し、テストコードから使用することができます。ニックネームを使用したメッセージはとてもユーザーフレンドリーなので自然言語のように読むことができます。特に画面要素については、要素を検索する際の実装の複雑さを隠蔽し、AndroidiOSのプラットフォームの差異を吸収します。結果として、1つのプラットフォームのテストコードを書いた後に、もう一つのプラットフォームとの差異をわずかな追加や変更で埋めることができます。

 

手動テストと自動テストの統合

テストエンジニアは手動テストのドキュメントと自動テストコードの両方を保守しなければならないので、テストコードをコンパクトに保つことは重要です。加えて、ドキュメントとテストコードが一つの成果物に統合されているか、一方を他方に変換できると理想的です。

Shiratesではテスト対象の機能が提供される前にテストコードを記載し、無負荷実行モード(NLRモード)でテストコードを実行し、出力されたログをSpec-Report(MS-Excelのワークシート)に変換できます。エンジニアはそれをもとにテスト内容を自然言語でレビューすることができます。機能が実装された後はそのモジュールをSpec-Reportを使って手動でテストすることができ、バグ報告や再テストを行うことができます。並行して実際に動作するテストコードを実装し、テストコードを実行し、テストコードそのものをデバッグことができます。製品のモジュールとテストコードがともに完成したら、自動テストによるリグレッションテストの環境が出来上がります。実行ログはSpec-Reportのフォーマットに変換できます。テストの結果はOK, NG, MANUAL, SKIP, EXCLUDEDなどが設定されます。MANUALは手動テストを実行する必要があることを意味します。SKIPはそのテスト項目が何らかの理由でスキップされたことを意味します。EXCLUDEDはテスト項目がそのセッションのスコープではないことを意味します。このように、テスト仕様と自動テストおよび手動テストの結果が一つのMS-Excelワークシートに統合されるので、テスト結果の集計を容易に行うことができます。

 

テンプレートコードの生成(マイグレーション向け機能)

既存の手動テストの仕様をShiratesのテストコードに移行する際には、一から記述するか、テンプレートコードジェネレーターを使用することができます。テンプレートコードジェネレーターはSpec-Reportの書式で記述されたMS-Excelワークシートを、scenario, case, condition, action, target, expectationのような関数を使用した構造的な関数呼び出しに変換し、Kotlinで記述されたJUnit 5のテストコードを出力します。他の手順や説明はmanual関数として出力されます。manual関数を実際に動作する関数に置き換えることでテストコードを実行できるようにします。

 

参照

https://github.com/ldi-github/shirates-core/blob/main/doc/markdown/quick-start.md#spec-report

 

 

業務アプリケーションのテストの話(その2):テストフェーズはテスト計画の中で定義する

開発フェーズの用語の混乱

システム開発のフェーズ(工程)に関する用語は混乱しています。統一されていないという言い方もできます。

たとえば、要求定義、要件定義は日本語ではそれぞれ別のような意味付けをされていても英語では共に requirements definition らしいです。

外部設計は基本設計あるいは概要設計と呼ばれたり、内部設計は詳細設計と呼ばれたりします。システムの方式設計はアーキテクチャ設計と呼ばれたり、基本設計と呼ばれたりすることがあります。「外部設計」と「システム方式設計」がそれぞれ「基本設計」を名乗るのは混乱以外の何物でもありません。そもそも「基本」って何?ってことが曖昧です。

また、同じ用語を使っていたとしても、組織や個人によってその言葉の定義が微妙にずれていることがあります。したがって、プロジェクト計画時や契約時に各工程の成果物の定義とカバーする内容を、成果物の名前だけでなく、その書きっぷりに踏み込んで合意しておかないと、納品時の揉め事の原因になります。

テストのフェーズに関する用語も同様に不統一です。しかし、テストにおいてはより複雑です。正確には、プロジェクトの前提条件を考慮した上で、全体テスト計画を立案する中でテストフェーズを定義し、関係者で認識を合わせる必要があります。

テストのフェーズを定義する際に意識すべき要素として以下のものがあります。

  • テストレベル
  • テスト環境
  • テスト実施組織

テストレベル

システムの部品同士を接続することを結合、または統合といいます。最も小さな部品から始めて段階的に結合(統合)しテストしていくことをボトムアップテストと呼びます。また、結合(統合)したときのテスト対象の粒度でテストを分類したものをテストレベルと呼びます。具体的には単体テスト結合テストシステムテストなどがあります。テストフェーズはまず、これらのテストレベルに対応して計画を開始し、単体テストフェーズ、結合テストフェーズ、システムテストフェーズとします。

ただし、システムテストフェーズは総合テストフェーズと呼ばれることが多いため、以下では総合テストフェーズとします。

テスト環境

テストを実施する環境はテストフェーズを細分化したり統合したりする要素となります。テスト環境は具体的には以下のようなものがあります。

開発環境(ベンダ内)

  • 開発者のPC
  • 開発用サーバー(群)

結合テスト環境(ベンダ内)

  • テスターのPC
  • 結合テスト用サーバー(群)
  • 性能テスト用サーバー(群)

結合テスト環境(顧客内)

総合テスト環境(顧客内)

  • 総合テスト(業務シナリオテスト)用サーバー(群)
  • 総合テスト(性能テスト)用サーバー(群)

運用テスト環境(顧客内)

  • 運用テスト用サーバー(群)

本番環境(顧客内)

  • 本番用サーバー(群)

テスト実施組織

これらの環境の上で、誰が、何をテストするのか作業計画を行うことでテストフェーズが定まります。誰が、何をテストするのかは、会社組織やプロジェクトによって決まります。

テストフェーズの例(自社サービス開発)

たとえば自社サービスを開発してクラウドに公開しているような企業で、製品開発チーム、テストチームが常時設置されているとすると、テストフェーズを以下のように定義することができます。

単体テストフェーズ

  • 開発用PC、開発用サーバー(群)で実施する
  • 開発者がxUnitでクラスを自動テストする

結合テストフェーズ

  • 開発用PC、開発用サーバー(群)で実施する
  • 開発者が画面・帳票・バッチを手動でテストする

総合テストフェーズ

  • テスト用PC、総合テスト用サーバー(群)でテストする
  • テストチームが画面・帳票を手動でテストする
  • 開発者がバッチを手動でテストする

この例ではxUnitを使用してクラスを自動テストする工程を単体テストフェーズ、画面・帳票・バッチのようにアプリケーションとして操作可能なものを手動でテストする工程を結合テストフェーズとしています。これは単体=クラスという考え方に基づいています。

一方、単体=機能(画面・帳票・バッチ)ととらえる考え方もあり、SIerの場合は単一の機能をテストするのを「単体テストフェーズ」、機能をいくつか組み合わせてテストするのを「結合テストフェーズ」と呼ぶことが多いと思います。この場合、単体=クラスの意味での単体テストは実施しないことがあります。

テストフェーズの例(受託システム開発

別の例として、システムを受託開発で構築する場合は、自社、顧客、他ベンダと協力してテストを計画する必要があります。この場合、例えばテストフェーズを以下のように定義することができます。

単体テストフェーズ

  • 開発用PC、開発用サーバー(群)で実施する
  • 開発者がxUnitでクラスを自動テストする ※実施しない場合もある
  • 開発者が個々の機能(画面・帳票・バッチ等)を手動でテストする ※こちらは必ず実施する

内部結合テストフェーズ

  • ベンダ内の結合テスト用PC、結合テスト用サーバー(群)で実施する
  • ベンダ内のテストチームが機能(画面・帳票・バッチ等)を組み合わせたシナリオをもとに手動でテストする

外部結合テストフェーズ

  • 顧客内の結合テスト用PC、結合テスト用サーバー(群)で実施する
  • 自社の開発者と、他社の開発者が、互いに対向するシステムとのインターフェースを手動でテストする

総合テストフェーズ(業務シナリオテスト)

  • 顧客内のテスト用PC、業務シナリオテスト用サーバー(群)
  • 顧客内のテストチームが画面・帳票を手動でテストする
  • 開発者がバッチを手動でテストする

総合テストフェーズ(性能テスト)

  • 顧客内のテスト用PC、性能テスト用サーバー(群)
  • ベンダの性能評価担当者が画面・帳票・バッチを性能評価する 

この例では、テストレベルが「結合テスト」とされる機能(画面・帳票・バッチ等)が開発者によって単体テストフェーズで実施されます。その他の部分はシステム間のインターフェースによって区切られるベンダの担当範囲によって、内部結合テストフェーズと外部結合テストフェーズに分割して実施されます。

 

このように、自社の中で閉じた開発と、顧客や他のベンダと作業分担して行う開発とでは、テストフェーズの定義の仕方が大きく異なります。

結合テスト」という用語を使ったとき、相手は違う内容を思い浮かべているかもしれません。認識齟齬があると後に問題が発生したときに揉める原因となります。

 

したがって、特定のテストフェーズの意味を確認してから関係者とテストに関する調整をすることが大変重要です。

 

業務アプリケーションのテストの話(その1)

テストについて書いていく

ブログ更新するのは一年ぶりです。システム開発の上流工程と下流工程を行ったり来たりして、それなりに楽しいエンジニアライフを過ごしています。これまでテストに関する記事を書いたことはありませんが、ネタがそろってきたので書いて行こうと思います。

 プログラマはテストが苦手

プログラマはテストに対して苦手意識を持っていたり、必要性はわかるんだけど面倒なのであまりやりたくないと考えたりしがちです。おそらく背景には

  1. テストに関する十分な教育を受けていない。作るのは好きでも、テストへの興味が薄いので自分で勉強しようとしない
  2. 自分が作ったコードの欠陥を自分で発見するのは、先入観があるので難しい
  3. プログラマの最大の関心事は品質ではなく、納期を遵守した製品のデリバリー

といったことがあると思います。

規模が小さいプロジェクトだと、少数のエンジニアで開発もテストも兼務してやることが多いと思います。一方で、テスト専任者またはテストチームを設置することで上記の2と3はある程度解決します。作業を分担することで開発者の負担を減らせるうえ、期間短縮および第三者の視点による品質向上が期待できるでしょう。

一方で、1の「テストに関する十分な教育を受けていない」という問題はわりと根深い問題です。諸先輩方も含め、テストタスクのあるべき姿をきちんと指導できる人は少なく思います。 

 テストが好きな人

個人的には、開発が大好きな人にはたくさんお目にかかれても、テストが好きで好きでたまらないという変態(暴言)にはお目にかかる機会はあまりありません。ただし、テストに向いている人というのは、ある種の特性を持っている気がします。

  • コツコツやるのが得意。マメである
  • 品質向上に貢献できると嬉しい
  • 物事の不備を指摘することに躊躇がなく、性格が悪い(いい意味で)
  • 独創的で、たまに他人が思いつかないような視点で不具合を見つけることがある

 こうして列挙してみると、基本的にせっかちなプログラマという人種とは真逆の存在に思えなくはないです。

独立したテストチームの有効性

システム開発の現場においては、開発チームとは別に独立したテストチームを設置すると品質は向上する傾向があります。開発チームは製品を産み出すことに、テストチームは品質確認に、それぞれ集中できます。

また、テストチームがテスト仕様書を作成する過程で、要件定義書や外部設計書に対する第三者レビューの効果があり、設計不備を早期に発見することにつながります。

なお、テストチームが担うテスト工程は結合テスト以降であり、 単体テストは実装担当の開発者自身が行います。

 

 

1回目は以上です。それなりに書くのは疲れます。

次回は混乱するテスト工程の呼び方について書こうと思います。

 

Node.jsでexceljsを使う(その1)

Node.jsでExcelの処理をしたいと思いました。

いろいろライブラリがあるのですが、APIが直感的なのでexceljsがよさげだと思いました。

https://www.npmjs.com/package/exceljs#reading-xlsx

でも、このドキュメントはちょっと不親切なので、初心者にはわかりにくいです。そもそもNode.jsそのものに慣れていないので、非同期I/Oの扱いがよくわからんでかなり悩みました。以下の記事を読んでPromiseパターンを理解すると、だんだん書き方が分かってきました。

 

参考にした記事

俺たちはJavaScriptの非同期処理とどう付き合っていけば良いのだろうか - Qiita

JavaScript Promiseの本

 

試しにTypeScriptでサンプルコードを書いてみました。


// exceljsで複数のExcelファイルを読み込んでファイルとシートの一覧を作成する
// TypeScriptのサンプルです。

import * as Excel from 'exceljs';
import * as path from 'path';
import * as fs from 'fs';

// 処理対象のExcelファイルのリストを作成します。
let dataDir = path.resolve("testdata");
let filelist = fs.readdirSync(dataDir).map(f => { return path.join(dataDir, f); });

// exceljsはファイルの読み込みに非同期のメソッドしか提供していないので、promiseパターンで実装します。
// まず、ファイルリストに対応してWorkbookの読み込みを行うPromiseのリストを作成します。
let promises = filelist.map(file => {
    let workbook = new Excel.Workbook();
    return workbook.xlsx.readFile(file) // readFileはPromiseを拡張したPromishを返します。
        .then(() => {
            // workbookにはfileの情報が含まれないので、fileとペアにしてresolveします。
            return Promise.resolve({ file: file, workbook: workbook });
        });
});

// すべてのPromiseを実行します。
Promise.all(promises)
    .then(function (results) {
        // ファイル、シートID、ワークシート名をコンソールに出力します。
        results.forEach((x) => {
            let workbook = x.workbook;
            workbook.eachSheet((worksheet, sheetId) => {
                console.log(x.file + "," + sheetId + "," + worksheet.name);
            });
        });
    }).catch(function (err) {
        console.log(err);
    });

実行結果

f:id:wave1008:20170524012314p:plain

 

いい感じじゃないですか。

exceljsでExcelの処理がどこまでできるか興味あります。

 

オッサンが始めるAngular(その1):Hello World

Angular 2に入門しようと思ったらいつのまにかAngular 4になっていました。

時の流れは早いものです。

Angularのチュートリアルで勉強します。

 

エディタの用意

Angularをインストールするまえに、エディタをインストールします。エディタは好きなもの使えばいいですが、ここではVSCodeを使ってみます。

 

f:id:wave1008:20170511232028p:plain

f:id:wave1008:20170511232055p:plain

f:id:wave1008:20170511232102p:plain

f:id:wave1008:20170511232111p:plain

f:id:wave1008:20170511232118p:plain

f:id:wave1008:20170511232123p:plain

f:id:wave1008:20170511232127p:plain

f:id:wave1008:20170511232143p:plain

 

 

CLI QUICK START

AngularのチュートリアルCLI QUICK STARTをやってみます。

CLI Quickstart - ts - CLI-QUICKSTART

f:id:wave1008:20170511232859p:plain

 

【超手抜き翻訳】 

Angular CLIはAngularで開発する際に利用するコマンドラインインターフェースです。

このガイドの目的はAngular CLIを使用してTypeScriptで記述したAngularのアプリケーションをビルド・実行することです。

以下のステップで説明します。

  1. 開発環境のセットアップ
  2. プロジェクトとスケルトンアプリケーションの作成
  3. アプリケーションの実行
  4. アプリケーションの編集

 

Step1. 開発環境のセットアップ

Node.jsとnpmをインストールします。最低でもnode 6.9.x, npm 3.x.x を使用してください。

https://nodejs.org/en/download/

f:id:wave1008:20170511233618p:plain

 

f:id:wave1008:20170511233643p:plain

f:id:wave1008:20170511233650p:plain

f:id:wave1008:20170511233655p:plain

f:id:wave1008:20170511233659p:plain

f:id:wave1008:20170511233704p:plain

f:id:wave1008:20170511233708p:plain

 

 nodeとnpmのバージョンを確認。

f:id:wave1008:20170511233945p:plain

 

Angular CLIをグローバルにインストールしてください。

f:id:wave1008:20170511234249p:plain

 

f:id:wave1008:20170511234307p:plain

完了。

 

Step2. 新規プロジェクトの作成

ng newコマンドでプロジェクト(my-app)とスケルトンアプリケーションを作ります。

f:id:wave1008:20170511234449p:plain

 

しばらく待ちます。長い。

f:id:wave1008:20170511234613p:plain

 

 my-appの下にいろいろ生成されています。

f:id:wave1008:20170511234715p:plain

 

Step3. アプリケーションの実行

プロジェクトのディレクトリへ移動し、サーバーを起動しましょう。

ng serveコマンドでサーバーを起動します。

f:id:wave1008:20170511234838p:plain

 

ブラウザでアプリケーションが開きます。

f:id:wave1008:20170511234917p:plain

 

Step4. Angularのコンポーネントを編集する

my-app\src\app にapp.component.tsが生成されています。(中身はTypeScript)

f:id:wave1008:20170511235148p:plain

 

app.component.tsをVSCodeで開きます。

titleのテキストを'My First Angular App'書き換えます。

f:id:wave1008:20170511235225p:plain

 

保存すると、ng serveがファイルの変更を検出してリビルドが実行され、ページがリロードされます。

f:id:wave1008:20170511235341p:plain

 

同様に、app.component.cssを編集します。

f:id:wave1008:20170511235502p:plain

 

保存すると、ng serveがファイルの変更を検出してリビルドが実行され、ページがリロードされます。

f:id:wave1008:20170511235631p:plain

 

 

CLI QUICKSTARTは以上です。