SpringBoot×GradleのWebアプリを作成してCircleCIで自動テストできるようにする

# はじめに
仕事でCI/CDによる自動テストを使ったJavaアプリに触れる機会があり、自分でもやってみようと思い簡単なアプリで再現してみることにした。

# 環境
Java 11.0.8
Gradle 7.1.1
CircleCI 2.0

# CircleCIにサインアップする
今回はCircleCIを使ってCI/CDをすることにした。
なので、サインアップが必要。
といっても、GithubアカウントがあればSSOログインできるので、楽ちんである。
https://circleci.com/ja/

# Webアプリを作成
SpringBoot × Gradleの適当なWebアプリを作る。
詳しい手順は以下を参考にした。
[SpringBoot × Gradleでプロジェクトを作ってSTS(Eclipse)にインポートするまで](https://qiita.com/Sirloin/items/dda7651b58d579a19ca8)

今回はアプリ作成自体はメインではないので、HelloWorldに毛が生えた程度の簡単なアプリを作る。

Controller
```java:TopController.java
@Controller
@Slf4j
@RequiredArgsConstructor
public class TopContoller {
	private final TopService topService;
	
	@RequestMapping(value = "/top")
	public String top() {
		log.info("TOPページを表示します。");
		log.info("add result: {}", topService.add(1, 2));
		return "top";
	}
}
```

Service
```java:TopService.java
@Service
public class TopService {
	public int add(int a, int b) {
		return a + b;
	}
}

```

Test
```java:TopServiceTest.java
public class TopServiceTest {
	private TopService topService = Mockito.mock(TopService.class);
	
	@Test
	public void addTest() {
		topService.add(Mockito.anyInt(), Mockito.anyInt());
		Mockito.verify(topService, times(1)).add(Mockito.anyInt(), Mockito.anyInt());
	}

}
```

HTML
```html:top.html
<html>
	<body>
		<h2>Hello World!!</h2>
	</body>
</html>
```

# CircleCiの設定をymlファイルに記述する
CircleCIを使用するためには、プロジェクトのルートディレクトリに`.circleci/config.yml`を作成しそこに設定を記述する必要がある。
[公式リファレンス](https://circleci.com/docs/ja/2.0/configuration-reference/)を見ながら色々触ったが、最終的には↓のようにした。

```yml:config.yml
# Java Gradle CircleCI 2.0 configuration file
# See: https://circleci.com/docs/2.0/language-java/
version: 2

# Define a job to be invoked later in a workflow.
# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
jobs:
  build-job:
    # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub.
    # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor
    docker:
      # specify the version you desire here
      - image: cimg/openjdk:11.0.13-browsers

    working_directory: ~/repo

    steps:
    # ソースコードをworking_directory(~/repo)に展開
      - checkout
      - run: 
          name: ビルド＆テスト実行(compileJava, compileTestJava, test)
          command: ./gradlew test
  deploy-job:
    docker:
      - image: cimg/base:2022.03
    steps:
      - run:
          name: デプロイ
          command: echo "deploy completed."
workflows:
  version: 2
  test-and-deploy:
    jobs:
      - build-job
      - deploy-job:
          requires:
            - build-job
          filters:
            # mainブランチへのコミット時のみdeploy-jobを実行
            branches:
              only:
                - main
```

## jobs
ここに、CIで実行したいジョブを定義する。今回は`build-job`と`deploy-job`を作成した。
ジョブの名前は予約語と被るとだめっぽい。

### 各jobの設定(build-job, deploy-job)
jobの詳細を設定していく。
### docker
ジョブの実行環境を指定する。docker/machine/macos/windowsが指定できるそう。
`docker`を選んだ場合は`-image`でイメージも指定する必要がある。

### working_directory
ジョブを実行するディレクトリを指定する

### steps
ジョブの名前、コマンドなどを設定する

#### - checkout
ソースコードをworking_directoryに展開する。これをしないと、後述の`./gradlew`が使えない。

#### run
名前と実際に実行するコマンドを記載する。
`name`で指定した名前がジョブ実行時のCircleCIの画面上で表示されることになる。

## workflows
ジョブの実行条件や、実行順序を設定する。
今回設定したのは、
* build-job -> deploy-jobの順に実行する
* deploy-jobはmainブランチが更新されたときのみ実行する。（デフォルトでは任意のブランチへのgit push時に自動実行される）

の二点。他にも色々細かい条件を指定できそう。

# 実際にCIを回してみる
まずはmainブランチにコミット。CircleCIの管理画面をブラウザから見ると、Dashboardにパイプラインが一個追加されているのが確認できる。
パイプラインの詳細を見ると↓のような感じ。
（mainブランチの更新なので、build-jobとdeploy-jobが実行されている）
![スクリーンショット 2022-04-03 15.07.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159675/a957c7f6-a187-92a0-57c0-a52bbfc771b5.png)

build-job
![スクリーンショット 2022-04-03 15.11.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159675/79ebc71d-fca5-26e1-98d2-1be2dd1ee3d4.png)

deploy-job
![スクリーンショット 2022-04-03 15.12.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159675/7ffc9900-9db4-8eab-cd7f-77faeda5640d.png)

mainブランチ以外からコミットした場合は、build-jobだけが走っていることがわかる↓
（※途中でジョブ名をリネームしたので`build`となってますが`build-job`のことです）
![スクリーンショット 2022-04-03 15.14.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159675/d3a70ea9-2d6c-8162-69fb-a6e269db9812.png)

# 余談１：ワークフロー実行時に「You’re using a deprecated Docker convenience image. Upgrade to a next-gen Docker convenience image.」と出る
dockerイメージにて`- image: circleci/openjdk:11-jdk`を使っているとこれが出る。
どうやら非推奨の古いイメージらしく、本記事投稿時点（2022/4/3時点）では`cimg/`で始まるイメージを使うのがよいとのこと。

`- image: circleci/openjdk:11-jdk`
↓
`- image: cimg/openjdk:11.0.13-browsers`
に変更すると、warnigは消える。

参考：https://dev.classmethod.jp/articles/using-circlecis-next-generation-convenience-images/

# 余談2：GradleでJUnitをコマンドから実行する
以下コマンドで実行可能。
```sh
$ gradle test
```
testタスクで、compileJava, compileTestJava, testの3つをまとめて実行してくれる（他にも色々やってくれてそう。このへんも調べてみたい。。。）

特定のクラス、メソッドに絞ってテスト実行したい場合は以下のように指定することができる。
```sh
$ gradle :[GradleのPJ名]:test --tests "[クラス名]$[@Nested配下のクラス名].[メソッド名]"
```

` -Dspring.profiles.active=test`などを付与して、application-test.ymlを見に行くようにする、なんてこともできる。

# さいごに
GitLabでもCI/CDができる仕組みがあるようなので、そっちもやってみたい。
GitLabだけでソース管理とCI/CDを一緒に管理できるので、便利かも？

おしまい。