見出し画像

Bitbucket Pipelinesでユニットテストを自動実行してみた話

こんにちは、Satchmoです。
ナビタイムジャパンで動態管理システムの開発・運用を担当しています。

今回は「Bitbucket Pipelinesでユニットテストを自動実行してみた」ことについてお話したいと思います。

実施に至った経緯

これまで私の所属しているプロジェクトでは、リリース前の作業として、ユニットテストを適宜Jenkinsまたはローカルで手動実行し、パスした場合のみmasterブランチへマージする運用となっていました。
ですが、手動実行となると人間ですので忘れてしまうことがあります。
また、ユニットテストが失敗した状態でmasterブランチへマージする可能性もあります。これまで、「ユニットテストを実行しておけば防げた」障害は発生していませんが、発生するのも時間の問題だと日に日に危機感を募らせていました。
そこで、自動ユニットテストを導入しようという事になりました。

導入の検討

自動ユニットテストの導入にあたり、以下の2つが候補として挙がりました。

Jenkins

最初の選択肢としてJenkinsが挙がりました。現状はJenkinsジョブでユニットテストを実行していたため、少し設定を追加するだけで可能だろうと想像していたためです。
JenkinsにはBitbucketプラグインがあり、Bitbucketにてwebhookを設定することで任意のジョブ(ユニットテスト)を自動実行することが可能のようでした。(詳細については割愛します)
ということで、Jenkinsでユニットテストを自動実行する方向で進めようと考えていました。ですが、この状態では未だ「ユニットテストが失敗した状態でmasterブランチへマージしてしまう」可能性があります。

Bitbucket Pipelines

上述したように、Jenkinsでは「ユニットテストが失敗した状態でmasterブランチへマージしてしまう」可能性があることがわかりました。
そこで、方法を模索していたところBitbucket Pipelinesを用いることで

  • ユニットテストを自動実行

  • ユニットテストをパスした場合のみmasterブランチへマージ

という2つの条件を満たせることがわかりました。
Bitbucket PipelinesとはBitbucket Cloudに組み込みのCI/CDです。
ということで、JenkinsではなくBitbucket Pipelinesを使用することとなりました。
※当社がBitbucketをオンプレミス版からクラウド版へ移行した際の記事もあるので是非!

やったこと

では、実際にユニットテストの自動実行の環境をつくってみます。やることとしては、bitbucket-pipelines.ymlをリポジトリのルートディレクトリに追加し、リポジトリの設定を変更すればokです。
以下、追加したファイルです。

image: maven:3.6.3-amazoncorretto-8
pipelines:
  pull-requests: 
    '**':
      - step:
          name: "test"
          services:
            - docker
          caches:
            - maven
            - docker
          script:
            - cp -f /usr/share/zoneinfo/Japan /etc/localtime
            - export AWS_ACCESS_KEY_ID=$NTJ_PICTOR_ACCESS_KEY
            - export AWS_SECRET_ACCESS_KEY=$NTJ_PICTOR_SECRET_KEY
            - export AWS_REGION=ap-northeast-1
            - docker build -t db
            - docker run -d db
            - mvn clean test

ファイル内の大まかな流れとしては

  1. パイプラインのトリガーを設定

  2. タイムゾーンを日本に設定

  3. Dockerにてテスト用DB構築

  4. テスト実行

となっています。 

パイプラインのトリガーを設定

pull-requests: 
    '**':

上記のように書くことで、すべてのプルリクエストが作成された場合にパイプラインが実行されるようになります。(プルリクエストが更新された場合も含みます)
これで自動テストができるようになりました。
他にも特定ブランチがコミットされたとき、など色々設定できるようなので公式ドキュメントを参照してみてください。

タイムゾーンを日本に設定

一部ユニットテストでサーバー時刻を使用していたので、日本時間に再設定します。

Dockerにてテスト用DB構築

テスト用のDBサーバーがありましたが、今回はBitbucket Pipelinesで完結させたかったためDockerでDBサーバーを構築しました。

最後にリポジトリの設定です。この設定をしないとテストが失敗していてもマージできてしまいます。リポジトリの設定については、以下記事を参考に同様の設定をしました。詳細は記事を参照ください。

これで

・ユニットテストを自動実行
・ユニットテストをパスした場合のみmasterブランチへマージ

という条件を満たすことができました!

ハマった点

ここまでスラスラと説明してきましたが、ハマった点が以下2点ほどありました。

  1. mvnコマンドが実行されない

  2. 時刻周りのテストがすべて失敗する

mvnコマンドが実行されない

ymlファイルの準備も完了しパイプラインを実行しましたが、いくら経っても実行が完了しません。ログを見てみたところ、テスト用DBの構築でパイプラインが止まってしまっているようでした。調べたところ原因は docker run をフォアグラウンドで実行していることでした。こちらは -d オプションを付け、バッググラウンド実行することで解決できました。

時刻周りのユニットテストが全て失敗

mvnコマンドが実行されない問題も解決し、テストを実行することができました。ですが、時刻周りのユニットテストが全て失敗していました。ユニットテストについては書き換えを一切行っていなかったので、原因が今回の対応であることはすぐに分かりました。
テスト結果を確認したところ、期待値と実際の値が全て9時間ズレていたので、タイムゾーンが日本じゃない?という予想のもと、以下のようにタイムゾーンを再設定することで解決できました。

cp -f /usr/share/zoneinfo/Japan /etc/localtime

まとめ

いかがでしたでしょうか。
何点かハマった点がありましたが、比較的簡単に条件を満たした自動テスト環境を作ることができました。また、自動ユニットテスト環境を構築することで大きな安心感を手に入れることができました!
今後はコードの静的解析、デプロイなどもしたいなぁ、なんて想像しています。
みなさんの参考になれば幸いです。

最後までご覧いただきありがとうございました!🤩