2017.03.23

Codeceptionの結果をBambooで自動解析する際の問題点と対処法


はじめまして。次世代システム研究室アルバイトのY.K.です。

私の参加しているプロジェクトではCodeceptionの結果をBambooを用いて自動解析しています。
今までの取り組みは下記を参照してください。

ここからテスト結果をBambooのAPIを用いて解析することを行いました。
解析までの道のりとぶつかった問題点、現在の対処法を共有します。

JUnitParserを用いたテスト結果のパースとAPIによる取得の流れ

取り組んだことの流れを説明します。
  • リリース用ブランチへのプッシュを検知
  • Codeceptionによるテストを自動実行し、結果をXMLで出力
  • JUnit Parserによるテスト結果の自動解析
  • Bamboo APIを用いたテスト結果の取得
これらの機能を組み込んで開発効率を上げようとしたのですが、
いくつか問題が発生したので共有します。

問題点1: テスト件数の不一致

まず最初にぶつかった問題はテストの実行数と出力結果数が合わないということです。
失敗したテストがあっても無視されてしまい失敗が0件と表示され、
問題ないように振舞われるケースも確認できました(これは困る!!!)。

結果数が合っていたテストのxmlとそうでないxmlを見比べたところ
testsuiteのネストの数が違うことがわかりました。

件数が一致していたxml例(testsuiteは1階層)
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
  <testsuite...>
    <testcase .../>
    <testcase .../>
  </testsuite>
.
.
.
</testsuites>
件数が一致しなかったxml例(testsuiteは2階層)
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
  <testsuite...>
    <testsuite ...>
      <testcase .../>
      <testcase .../>
    </testsuite>
  </testsuite>
.
.
.
</testsuites>
深さが変わってしまう原因はCodeception側にありました。
CodeceptionにはDataProviderという便利な機能があります。

テストを実行するCestファイルにおいて配列を指定しておくと配列の要素分だけ勝手にテスト内容を繰り返してくれます。
これによって様々なステータスを持つデータを一気にテストすることが可能です。
    protected function _users()
    {
        return  [
            ['user_id' => "hogehoge", 'password' => "testtest"],
            ['user_id' => "hogehoge2", 'password' => "testtest2"],
        ];
    }

    /**
     * @param UserTester $I
     * @param Example $example
     * @dataprovider _members
     */
    public function test(UserTester $I, Example $example)
    {
        // テスト内容
    }
これを利用した結果、testのxmlがネストすることがわかりました。
しかし、この便利な機能を使わない手はないので、これを利用したまま何とかテスト結果がパースできないか、試行錯誤することに。。。

対処法

やはりネストが深いtestsuiteは無視されているようで、現段階(2017年3月22日)では対応されていないことがわかりました。
Junit XML Parser of bamboo does not separate test cases by their test suites

You are right .. the bamboo xslt transform template ignores the testsuites.
this is what bamboo thoughts the xml is and transforms that accordingly. ignoring multiple testsuite to group test case as if there were just one testsuite.
If you want to generate different report than t he one junit task generates in bamboo you might have to write your own plugin.

testsuiteが無視される場合があるよ(testsuitesの直下のみ対象、それ以上だとグループ化される)、
違う形式のxml(report)使うなら自分でプラグインとか作ってねって書いてあります。

実際に実行されるテストの数はtestcase数なので、
2つ以上testsuiteがネストしている部分から最深のtestcaseを抽出すれば解決です。

今回は2階層目のtestsuiteを削除するという簡素な方法で対応しました。

sed -i '/\s\s\s\s<\/\?testsuite.*/d' path/report.xml
上手くいくと以下のようにビルド結果のページにテストの失敗件数が表示されます。

bamboo_test

問題点2: BambooAPIでのテスト結果取得ができない

もう一つの問題はBambooのAPIを用いたbuild-taskの結果の取得がうまくいかないことでした。
Bambooにはビルドの結果を取得できるAPIが存在します。
(http(s)://{{bamboo-url}}/rest/api/latest/result/{{bamboo_build_key}}.json)
このAPIを用いてテストの成功、失敗件数を取得することを試みました。

しかし、テストとパースを行っているbuild taskの中では取得することができません。
走っているタスク自体の結果を取得しなくてはならないのですが、
すべてのタスクが終了しないとテスト結果がAPIに反映されず、stateがUnknownという状態に。。。
{
...
  "state":"Unknown",
  "buildState":"Unknown",
...
}
テスト結果が取得できればこのようなプロパティが返ってくることになっています。
{
...
  "successfulTestCount":2,
  "failedTestCount":6,
  "quarantinedTestCount":0,
  "skippedTestCount":0,
...
  "state":"Failed",
  "buildState":"Failed",
...
}

対処法

この問題の解決方法はだいぶ荒療治ですが、
ビルド中でもビルドのID(bamboo_build_key)は取得することが可能なのでそれを用います。

手順としては
  • ビルド中にビルドIDをファイルに出力
  • テストが終わったらファイルのビルドIDを用いてAPIを叩く
  • APIの出力を解析
となります。

ビルドIDは以下のようなBambooの予約語で出力できます。
echo ${bamboo.buildResultKey} >> path/build_id.txt
APIを叩くタイミングは
  • 他のビルドタスクにテストのタスクが終わったことを通知する
  • IDを記載したファイルの情報を確認するタスクを走らせる
のどちらかでスムーズなものが確立できます。

今回は数分ごとにIDを記載したファイルを見てAPIを叩くバッチのようなビルドタスクを
BambooのScheduled Triggerを用いて作成しました。

結果

これらの問題を解決した後に、チャットワークに通知することにしました。

chatwork
これによってStashへのpush結果を自動でテストしてテスト結果を通知することが可能になりました。

まとめ

いかがでしょうか。
今回はテストの自動化について共有しました。
自動化はその労力を補って余りある効果を発揮してくれます。
テスト以外にもどんどん自動化を進めて運用、開発の手間を減らしていきたいですね。

次世代システム研究室では、アプリケーション開発や設計を行うアーキテクトを募集しています。アプリケーション開発者の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ 募集職種一覧 からご応募をお願いします。