0
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

Outsystems Platform でUTFを使ってテスト自動化できたけど結局お蔵入りしたお話(実装メモと黒歴史)

はじめに

  • ローコード型超高速開発ツールOutsystems Platform(OSP)のプラクティスメモです
  • PC内のドキュメントを整理していたら過去の試行錯誤のメモが発掘されたので共有します
    • 黒歴史としてこのままそっ閉じすることも考えたのですが、せっかくなら同じことに悩んでいる人の一助にでもなればと思い
  • フレームワークを使ってテスト自動化のテストケースをOSP上で実装することはできましたが、ある理由でお蔵入りしたので、その話をします
  • Traditional Webしかなかった時代のお話です。Reactive Webで同じように再現できるかは確認していませんので、もろもろご了承ください

当時の背景

  • 当時、モバイルアプリのサーバ側の処理をOSPでREST-APIで作りまくる状況にいました
  • アジャイル開発ということで段階的・継続的リリースを予定していたので、当然のようにテスト・ドリブンによる開発が必要だ!という意気込みで、方法を模索しました
  • APIなので画面(OSPで言うところのInterface層)はなく、Logic層・Data層だけのテストだったので、個人的に好きだったSeleniumは使えませんでした(そもそもWebアプリでもないので)

Unit Testing Frameworkを採用

  • 単体テストを組み合わせてテストケース・テストシナリオを作っていくことにしました
  • 色々と調べた結果、実績と再現性から、「Unit Testing Framework」のOSPのForgeを採用することにしました
    • このForgeの役割は、主に次の2つです
    • 便利なテストメソッドの関数の提供→テストメソッド集をつくる
    • テスト管理画面でテストメソッド一覧を取得→実行→結果確認する
    • Foge中身のモジュールを解説すると、次のような形になります utf_1.png

テストメソッドの作り方

  • 実際のテストメソッドの作り方は次のような流れです
    • 「UTF_Template」をクローンする
    • 「Logic層」>「SOAP」配下に、テストメソッドのアクションを作っていく
      • ①テストをするために必要な初期値をAssignする(固定値、テストデータなど)
      • ②テストしたいロジック(or アクション)を呼び出す
        • お分かりのように、テストしたいロジック部分は、サーバアクションとして事前にコンポーネント化してあげる必要がある
        • この時、後で実績値が必要になる、すわなちDBの更新結果などを検証(Assert)する必要があるので、処理結果を戻り値にするか、当該レコードを特定して後でAggregateなどで持ってこられるようなIDなどの戻り値を返してあげる必要がある
      • ③Forgeが提供している色々なAssert_XXのアクションを使って検証する
        • 例:「Assert_AreEqual_Integer」のプロパティ値
          • TestRunUnitTestId:テスト管理画面で実行する時に自動で渡される引数を設定
          • Expected:期待値を設定する(固定値で入れるか、外部から値を取得して設定)
          • Actual:実績値を設定する(テストしたいロジックを実行した結果を取得して設定)
          • Context:人間がテスト管理画面でどんなテストかを確認するための説明(要は、実際の動作には影響しない内容)
          • ContinueOnFail:検証結果が失敗だったら、処理を継続するかを設定
      • (一つのアクションで他にテストしたい内容があれば、②や③を好きなだけ追加する)
      • ④最後にAbortTransactionする(コミットしてしまうと、同じテストデータが使えなくなるので)
    • テストメソッドのアクションができたら、Publishする
  • 例:RegUser(ユーザの登録)のテストメソッド utf_2.png

Web画面で作成したテストメソッドの取得・実行・結果確認

  • Forgeの中にある画面モジュール(Webアプリ)「UTF」を開いて画面上で操作するだけでOKです
    • 何か特別にカスタマイズする必要などはありません
  • 流れとしては次の通りです
    • ①Planタブの「ScanForTest」を実行し、作成したテストアプリ or テストメソッドを取得する
    • ②Planタブの中にある任意のテストアプリ or テストメソッドを選んで「Run」する
    • ③Resultタブで実行結果を確認する
    • ね、簡単でしょ?
  • テスト管理画面のイメージ utf_3.png utf_4.png

なんで頓挫したのか(注意:UTFがわるいという話ではない)

  • しっかり動いて、品質は担保できました!
  • しかし、テストドリブンでない場合に比べて、3倍の時間がかかりました!!
  • 理由としては。。。
    • ①テストデータを準備するのがとにかく大変
      • 期待値をハードコーディングするのはナンセンスすぎたの、自分は「テストデータ管理用Web画面」を作成して頑張ろうとしました
      • しかし、本アプリではID生成の際にGUIDを使っていたので、固定的なテストIDをつくることができませんでした
      • その結果、テストメソッド*テストケースごとに利用するテストデータを識別するための複合キーなんかを準備し、それをテストメソッド内で取得するようになって。。。というように、管理がめちゃくちゃ大変でした。。。
    • ②単純にテストの実装ボリュームが多くて人手が足りない
      • (当たり前のことですが。。)正常系、異常系、準正常系のテストケースを机上で設計するだけならそこまで時間がかからないのですが、これらのテストケースを実装するとなると、単純に実装ボリュームが増えて大変でした
      • 特に、検証する値が多かったので、個々にAssertを作って期待値と実績値を設定していくのがひたすらきつかった記憶があります
    • ③途中での実装変更が多く、テストケースの改修も頻発した
      • ビジネス要望や(モバイルアプリの)クライアントサイドとの連携調整の兼ね合いで、サーバサイドで扱う情報が増えたり、そもそも処理が変更になることが継続的に多かったです
      • そうなると、時間をかけて作っていたテストケースも改修だとかさらに追加実装になるので、つらいことになりました

最終的には...と反省点

  • UTFを使ってのテストドリブンでの実装は諦めました
    • 当時、サーバサイドを3ヶ月*1人で作って検証版アプリをリリースさせなければという制約があり、人手を確保できず、確保できたとしても改修が入ると苦労して作ったテストメソッドは無駄になってしまう状況だったので。。
  • 反省として、とにかく、テストデータの管理については、よくよく検討する必要があります
    • 当時は急拵えで走ってしまったところはあるのですが、とはいえ、今振り返っても素晴らしいアイデアはすぐには出てこないので、こういいうのはチームで最初か検討した方が良いと思います
  • また、テスト自動化をするタイミングも注意が必要と考えます
    • ウォーターフォールチックに後戻りが基本無いはず(無いとは言っていない)の場合だと、まだ良いかもしれませんが、アジャイル開発の変動要素の多い序盤からテスト自動化をするのはセンスがなかったかもしれません
    • 自動化をするにしても、リリースの手前あたりで基本が固まっている段階で、それも全てではなく大事な点に限定して進める方が良いと考えています

おわりに

  • 最後は自分のイケていない黒歴史の公開になってしまいましたが、どこでも「あるある」だと思うので、反面教師として参考にしてもらえれば幸いです
  • なお、OSPでUTFを使ってテスト自動化をすること自体は全然問題ないので、その点は安心していただければ
  • それでは、みなさま。良いテストライフを

OSP関連記事

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
0
Help us understand the problem. What are the problem?