たなかのJava日記

どんなことをやったか(学んだか)、どこで詰まったか(わからなかったか)、どこで工夫したかの記録です。

Git-コミット-

Gitでのコミットについてまとめました。

■コミット
コミットとは、1つ以上のファイルの状態を履歴で確定させる操作です。
意図的なセーブポイントみたいなもので、何度でも行うことができます。
コミットしておくと、助かることがあります。
あとからいつでもコミットしたときの状態に復旧したり、
ファイルの状態を比較したりできたりするためです。
コミットを行うには[Ctrl]+[K]を押して「コミットツールウィンドウ」を表示します。
とはいえ、コミットばかりするのも考え物です。
どのようなタイミングでコミットを行えばよいのかは以下になります。

■コミットを行うタイミング(はじめのうちの目安)
・プロジェクトを作成した後
・テストコードを実装した後
・機能の実装を終えてテストケースも通った後
リファクタリングを行う前後
・文法に自信がないうちはコンパイルが通ったタイミング

■コミットツールウィンドウ
コミットツールウィンドウは、コミットを行う[Ctrl]+[K]を押した後に開かれる画面です。
大きく2種類のリストがあります。
・デフォルト変更リスト(変更)
・バージョン管理外ファイル

最初はすべてのファイルが「バージョン管理外ファイル」となっています。
ですので、自らファイルを選択しそれが「履歴管理」の対象となる仕組みです。
選択の取捨選択をし、コミットを押すことでコミットは実行できます。

そもそも、コミットの対象はどのように取捨選択しているのでしょうか。
IntelliJ IDEAでMavenを使用している場合には、
基本的に3つのファイルに分けられていることをまずは知る必要があります。

IntelliJ IDEAが自動的に作成する.ideaという管理用のファイル
Mavenのプロジェクトファイルであるpom.xmlファイル
・クラスやテストコードの.javaファイル

結論から言うと、一人で開発を行っている場合はこれら全て選択しても問題ありません。
しかし、共同開発を行う場合はコミット対象にしてはいけないファイルが
ルールとして設けられている場合があります。
例えば、「.ideaディレクトリ」やEclipseの「.classpth/ .settings」
といったIDE固有のディレクトリ/ファイルです。
チームでどのような運用になっているのか確認してからコミットするようにしてください。
ideaディレクトリ内には共有すべきでないファイルもあります。
詳しくは下記のWebページを参照してください。
https://support.samuraism.com/jetbrains/faq/share-idea-directories

とはいえ、特定のファイルやディレクトリをコミット対象から毎回選択を外したりするのは面倒です。
人間なのでミスや漏れもあるでしょう。
特定のファイルやディレクトリをコミット対象から常に外すには、
「gitignoreファイル」にファイルを作成し、ある記載を行います。

■gitignoreファイルの作成
ファイルやリソースファイル、HTMLファイルといった、
プロジェクトで必要となるファイルはGitで履歴を管理します。
.classファイルや.logファイルなどは、コンパイルや実行といった操作によって自動的に生成されるものです。
ソースコードと共に管理する必要はないでしょう。
Gitでは.gitigoreというファイルに管理が不要なファイルの一覧を記述しておくことでコミットを避けることができます。
.gitignoreファイルを作成するには、
[Alt]+[1]キーでプロジェクトツールウィンドウへ移動します。
さらに、プロジェクトのルートディレクトリ(プロジェクトツールウィンドウで一番上に表示されるディレクトリ)
にフォーカスを置いた状態で、[Alt]+[Insert]キーで
新規ファイル作成のポップアップを表示して[ファイル]を選択します。
ファイル名として「.gitignore」を入力して確定すれば作成完了です。
ここには無視したいファイル名やディレクトリ名を指定します。
ワイルドカードの使用が可能です。

※記載の例
*.class
*.log
target

targetディレクトリを記載している理由は
Mavenでビルドした結果が出力されるファイルだからです。
開発が進むにつれてコミットしたくないファイルが増えたら
その都度、追加してください。

■その他
二回目に河野コミットを行う場合は、変更リストのファイル名をダブルクリックするか
エンターキーを押すことで、差分を表示することができます。
コミットする前に間違った修正が行われていないか確認ができます。
また、Gitログの確認もできます。
[Alt]+[9]キーで、これまで行ったコミットとそれぞれのコミットログ、
変更が行われたファイルの一覧や差分を管理することができます。

IntelliJ IDEAの補完機能

■補完の候補表示と補完確定
var str = "こんにちは"
str.indexo
ここまで入力すると補完候補がポップアップウィンドウに表示される。
補完候補のうち、一番上に表示されているもので良ければ
[Tab]キー or [Enter]キーで確定できます。
2番目以降を選択したい場合は、候補を絞り込むかカーソルキーで選択します。

■補完の候補”再”表示と補完確定
すでに確定済みのコード内で、再度候補表示を出して書き換えたい場合は、
書き換えたい場所へテキストカーソル位置を移動して、
[Ctrl]+[Space]キーを押します。
補完するときは、[Tab]キーを押すとすで記載されていたキーワードを置換して確定してくれます。
※[Enter]キーで確定すると、置換されずテキストカーソル位置以降はそのまま残ってしまいます!

■import文の補完
IntelliJ IDEAでimport文が必要となるコードを書いていると、
java.util.List?(複数の選択肢)」といったポップアップが表示されます。
ここで[Alt]+[Enter]を押すと、importするクラス・パッケージが候補として表示されます。

■いい感じの修正
[Alt]+[Enter]はimport文の補完だけでなく、いい感じに修正してくれます。
特に黄色く警告が出ているコードは、より良いコードに書き直してくれる場合が多いです。

■for文
「fori」と書いてから[Tab]キーを押せば、forループを展開してくれます。
ループで使用する変数iは任意の名前で書き替えることも出来ますが、
多重ループでなければそのままでよいので再度[Tab]キーを押します。
そしてループ最大値を入力して再度、[Tab]キーを押せばforループの完成です。

■String型の変数を定義し、空の文字列で初期化(後置補完)
「"".var」と入力して[Tab]キーを押します。
すると、
String s = "";
という構文に展開してくれます。
[Tab]キーを押した直後のカーソル位置は変数名のところにあるので、
そのまま入力して[Tab]キーを押して確定してください

■後置補完の確認
"String型の変数を定義し、空の文字列で初期化"以外にも
後置補完はたくさんあります。
[Ctrl]+[Alt]+[S]でキー環境設定を開き、
[エディター]、[一般]、[後置補完]の順で進むと確認ができます。
独自の後置補完を定義することも出来ます。

■if文
「変数iが3で割り切れる」ことを示す式、
i%3==0を入力してから「.if」と入力して[Tab]を押します。
前にある条件式を使ったif文を構築してくれます。

i%3==0を入力してから「.not」と入力して[Tab]を押します。
前にある条件式を反転したif文を構築してくれます。

■System.out.println();
出力する構文は「sout」と入力してから[Tab]を押すと展開してくれます。
また、「変数名.sout」と入力すれば()内に変数名を入れてくれます。

■現在開いているファイルを実行
[Ctrl]+[Shift]+[F10]

 

「西暦からサッカーワールドカップ開催年」を判別する

サッカーワールドカップ開幕まであと7日です。
前のワールドカップはいつだったかな~と気になったので、
以前「西暦からサッカーワールドカップ開催年」を判別するコードを作成しました。

下記がJavadocを書いた際に作成したコードです。

 /**
     * 渡された西暦年がサッカーワールドカップ開催年であるかどうかを判定する
     * @param year 西暦
     * @return サッカーワールドカップ開催都市であればture
     * @throws IllegalArgumentException まだオリンピック開催が確定していない年を渡した場合
     */
    public boolean isSoccerWorldCupYear(int year) throws IllegalArgumentException {
        if (2026 < year) {
            throw new IllegalArgumentException("2026年までサポートしています。入力" + year);
        }
        return year % 4 == 2;
    }

サッカーワールドカップは、西暦を4で割って余りが2になる年に開催されます。
また、現時点では次回大会の2026年までの開催が確定しています。
その旨をコードに落とし込んだのですが、必ずしも4年に1度開催しているわけではありません。
例えば、同じく4年に1度開催しているオリンピックはコロナで延期になりましたね。
サッカーワールドカップも戦争で中止になった年があります。
ということは、このコードにはバグがあると言えます。
(他にも西暦18年は、4で割って余りが2になりますが、当然ワールドカップは開催されていません)
大した修正量ではないので、すぐに直してしまえばいいのですが、
Junitを学んだのでテストコードを書いてから修正を行いたいと思います。

テストを書く前に、まずはテスト項目を洗い出しました。
境界値下限 ⇒ サッカーワールドカップ開催以前の年はfalse
通常開催年 ⇒ 4年周期の開催年はtrue
非開催年 ⇒ 4年周期から外れる非開催年はfalse
中止年 ⇒ 戦争で中止になった年はfalse
延期開催年 ⇒ 4年間隔ではない例外的な開催年はtrue
サッカーワールドカップには延期開催年は無かったため、テスト項目から除外。
境界値上限 ⇒ 開催地が決定している年よりも後は例外発生

テスト項目をもとに、テストコードを書くと下記のようになりました。

package soccer;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

@SuppressWarnings("ALL")
class WorldCupTest {

    @Test
    void 境界値下限() {
        // サッカーワールドカップ開始以前
        assertFalse(new WorldCup().isSoccerWorldCupYear(1890), "1890年");
        assertFalse(new WorldCup().isSoccerWorldCupYear(1925), "1925年");
        assertFalse(new WorldCup().isSoccerWorldCupYear(1929), "1929年");
        // 初回開催年
        assertTrue(new WorldCup().isSoccerWorldCupYear(1930), "1930年");
    }

    @Test
    void 四年周期の開催年() {
        int years = {1950, 1986, 2002, 2018};
        for (int year: years) {
            assertTrue(new WorldCup().isSoccerWorldCupYear(year), year + "年");
        }
    }

    @Test
    void 戦争による開催中止年() {
        int years = {1942, 1946};
        for (int year: years) {
            assertFalse(new WorldCup().isSoccerWorldCupYear(year), year + "年");
        }
    }

    @Test
    void 境界値上限() {
        assertDoesNotThrow(

                     () -> new WorldCup().isSoccerWorldCupYear(2025));
        assertDoesNotThrow(

                     () -> new WorldCup().isSoccerWorldCupYear(2026));

        // 開催が決定している2026年より後は例外が発生すること
        assertThrows(IllegalArgumentException.class,
                () -> new WorldCup().isSoccerWorldCupYear(2027));
        assertThrows(IllegalArgumentException.class,
                () -> new WorldCup().isSoccerWorldCupYear(2028));
    }
}

このテストコードを実行するともちろん失敗します。
次に失敗したケースのテストが通るように実装を進めていきます。

package soccer;

public class WorldCup {
    /**
     * 渡された西暦年がサッカーワールドカップ開催年であるかどうかを判定する
     * @param year 西暦
     * @return サッカーワールドカップ開催都市であればture
     * @throws IllegalArgumentException まだオリンピック開催が確定していない年を渡した場合
     */
    public boolean isSoccerWorldCupYear(int year) throws IllegalArgumentException {
        // 境界値下限
        if (year < 1930) {
            return false;
        }
        // 戦争で中止
        if (year == 1942 || year == 1946) {
            return false;
        }
        // 境界値上限を超えたら例外発生
        if (year > 2026) {
            throw new IllegalArgumentException("2026年までサポートしています。入力" + year);
        }
        // 四年周期の開催年
        return year % 4 == 2;
    }
}

テストケースが通るようになりました。
今回は軽く実装していましたが、実装よりもテストを先に書く手法を
テスト駆動開発」と呼ぶらしく注目されている手法とのことです。

 

※コードのあちこちで文字サイズがバラバラだったり、表示がおかしかったりしますが、理由がわかりません。ご了承ください。

 

効果的にテストケースを書くためには

効果的にテストケースを書くためには

■バグを顕在化させることのできるパターンを網羅しているかが一番の鍵
テストは多くのパターンを列挙すればよいというものではない。
パターンが多いと実行時間が長くなってテスト実行が億劫になるデメリットもある。
パターンが多いとテスト自体のメンテナンス工数も増えてしまう問題もある。
このことから、テストに品質はパターン数ではなく、バグを顕在化させることのできるパターンを網羅しているかで決まると言えます。

■どのような箇所に、どのようにテストケースを書くのか
①条件分岐する箇所・境界値前後
「年齢によって酒の販売が許可される・されない」など、引数やその他条件によって動作が変わる。
このようなメソッドでは極力すべての条件分岐を網羅できるようにテストを書きます。
20歳未満は酒の提供禁止ですが、誤って20歳未満は提供可能な実装をしてしまうこともあるためです。
また20歳、19歳、21歳などの境界前後の値でも期待通りの動作かを検証する必要があります。

②異常値
プログラムを実装するときは正常動作することのみを検証しがちです。
テストケースを洗い出す場合は、異常値を渡すことも検討すべきです。
例えば、Stringの引数を受け取る場所でnullを渡したらどうなるのか、
年齢を受け取る場所で負の値を渡したらどうなるのか、などです。
nullや負の値を渡すことを許容しないのであれば、メソッドのJavadocにその旨を明記することが必要です。
また、許容しない値を渡したら例外IllegalArgumentExceptionが投げられることを確認するテストケースを書いたりすることで仕様が明確になります。

③不安な箇所
実装したあとで動作確認をしたくなるような、不安を覚える箇所にテストケースを書きます。
バグが発生していないことを確認、確信するための重要な箇所です(精神的にも)

④重要度の高い箇所、金勘定が関係する箇所
同じ画面表示という機能でも、社内向けシステムでレイアウトが崩れても業務に差支えはありません。
しかし、お客さま向けがめんで他人の個人情報が表示されてしまえば重大な障害になります。
また、株取引システムで株価の計算ミスがあれば、証券会社だけでなく経済も揺るがすことになります。
業務上、重要度が高くてバグの発生を許容しがたい箇所には優先的にテストを書くようにします。

⑤バグが判明した箇所
テストを十分に記述したつもりでもバグは発覚します。
バグが発覚した際、焦ってJUnitテストケースを書かずに実装コードを直してしまうと、
同様のバグが発生した際に検出できないだけでなく、
そもそも「バグを修正できた」、という確信を持つことができません。
バグを見つけたら直してしまう前に「現象を再現し、失敗する」テストケースを記述し、
その上で実装を修正するようにします。

⑥細かい粒度のテスト
単体テストは、メソッドやクラスを対象とした細かい単位のテストになります。
結合テストは、複数のクラスやメソッドを組み合わせた処理です。
総合テストは、一気通貫で動作を確認するテストです。
(システムにログインしてフォームに必要事項を入力送信を行うなど)
ユーザー目線に立つとシステムが動作している様子が分かりやすい総合テストを優先しがちですが、
テストする対象のコードが多ければ多いほど、シナリオは複雑になり、テストすべきパターンが漏れがちです。
単体テストで細かい粒度てテストがしっかりできていればバグが検出されにくくなります。
テストはより細かい単位でしっかりパターンを網羅しておくのが大切です。

⑦わかりやすいテストケース名
テスト対象のメソッド1つにつきテストメソッドが1つしかないのであれば、テスト対象のメソッドと同じでかまいません。
しかし、色々なパターンでテストをする分けている場合は、メソッド名を工夫するのが良いです。
add1()、add2()などというメソッド名でもコンパイルでき、テストは実行できます。
しかし、テストは一種の仕様書であり、失敗したときはバグ報告書でもあります。
対象のメソッドへどのような挙動を期待しているのか(仕様)、
どのようなシナリオでテストを行っているのか(失敗時のバグ報告)などが
わかるような、わかりやすいメソッド名が好ましいです。
またプロジェクトの公用語が日本語であれば日本語でメソッド名を書くのも有りです。
テストが失敗した際、どういった問題があるのか一目でわかります。

 

アサーションメソッドの種類

前回は実行結果が期待した値と等しいことを確認する、
assertEqualsメソッドを実施しました。
アサーションメソッドは他にも種類がたくさんあります。
今回はassertEquals以外の代表的なアサーションメソッドを確認します。

■代表的なアサーションメソッド
assertEquals(期待値, 式 [, メッセージ])
 ⇒式が期待値と一致することを確認する

assertNotEquals(期待値, 式 [, メッセージ])
 ⇒式が期待値と異なることを確認する

assertTrue(式 [, メッセージ])
 ⇒式がtrueを返すことを確認する

assertFalse(式 [, メッセージ])
 ⇒式がfalseを返すことを確認する

assertNull(式 [, メッセージ])
 ⇒式nullを返すことを確認する

assertNotNull(式 [, メッセージ])
 ⇒式がnullを返さないことを確認する

assertThrows(例外クラス, ラムダ式[, メッセージ])
 ⇒式が例外を投げることを確認する※Junit5から導入

assertDoseNotThrow(ラムダ式[, メッセージ])
 ⇒式が例外を投げないことを確認する※Junit5から導入

assertAll(ラムダ式...)
 ⇒複数のテストをすべて実行する※Junit5から導入

※Junit5から導入された新しいアサーションメソッドは、
引数、戻り値を持たないラムダ式を書きます。

■例外NumberFormatExceptionが投げられることを期待するテスト
assertThrows(NumberFormatException.class, () -> Integer.parseInt("¥10,000"),
                        "¥や,が入っているのでパース出来ない");

■例外が投げられないことを期待するテスト
assertDoesNotThrow(() -> new Calc().add(-100, 10),
                        "負の値を渡しても例外が出ない");

■複数のアサーションメソッドを必ず実行するテスト
通常、アサーションメソッドで失敗するとそこでテストメソッドの実行は終了します。
テストメソッド内でに複数アサーションメソッドメソッドが並んでいる場合、
一番最初に失敗するアサーションメソッドしか確認ができません。
assertAllメソッドを使えば、アサーションメソッドを含むラムダ式を複数記述できます。
ラムダ式はすべて実行され、失敗したラムダ式の一覧が報告されます。
似たテスト項目を列挙するときに使うとよいです。

以下はテストメソッド内に複数のアサーションメソッドを記載した例です。
※本当は例外は別のメソッドでやるべきです。
サンプルとして1メソッド内に複数のアサーションメソッドを記載しています。

package test;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CalcTest {

    @Test
    void add() {
        assertAll(
                () -> assertThrows(NumberFormatException.class, () -> Integer.parseInt("¥10,000"),
                        "¥や,が入っているのでパース出来ない"),
                () -> assertDoesNotThrow(() -> new Calc().add(-100, 10),
                        "負の値を渡しても例外が出ない"),
                () -> assertEquals(4, new Calc().add(2,2), "2 + 2 = 4"),
                () -> assertEquals(6, new Calc().add(2,4), "2 + 4 = 8")
        );
    }
}

Junitでテストケース実装、実装コードの修正を行う

 

//テストされるコード
package test;

/**
 * 足し算
 */
public class Calc {
    /**
     * 渡された2つの値で足し算を行う
     * @param a 一つ目の値
     * @param b 二つ目の値
     * @return 足し算の結果
     * @since 2022/11/12
     */
    public int add(int a, int b) {
        return a * b;
    }
}

//テストコード
package test;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CalcTest {

    @Test
    void add() {
    }
}

テストの中身はまだ実装していませんがテストコード内で、[Ctrl]+[Shift]+[F10]を押して実行してみます。

このショートカットキーを使用した時は、テキストカーソル位置で実行の動作が変わるので注意です。
・テストメソッド内にカーソル有⇒そのテストメソッドのみ実行
・テストメソッド外&テストクラス内にカーソル有⇒テストクラスすべてのテストメソッド実行

ショートカットキーを使用しない場合
・テストクラス横の[すべて実行]ボタンを押すと、テストクラス内全てのテストメソッドを実行。
・テストメソッド横の[一つ実行](▶)ボタンを押すと、そのテストメソッドのみ実行できます。

とはいえ、現状はJunitのセットアップができて、テストメソッドに何も実装していない状態です。
なので、実行してもテストは成功します。
今回はテストメソッド(addメソッド)内に次の行を加えてテストを実装します。

■追加する行
assertEquals(4, new Calc().add(2,2), "2 + 2 = 4");

・構文
assertEquals(期待値, 実際の値[, テスト内容を表すメッセージ]);

//addメソッドに追加
package test;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CalcTest {

    @Test
    void add() {
        assertEquals(4, new Calc().add(2,2), "2 + 2 = 4");
    }
}

★解説メモ
・assertEqualsはJunitが提供するアサーションメソッドと呼ばれるメソッド
・実行結果が期待した値になることを確認・検証するメソッド
アサーションメソッドは多数あるが、assertEqualsは最も基本的かつ重要
・ちなみにassertとは英語で「断言する」という意味で、
「このように動作すべきだ、そうでなければバグであると断言する」といった意味で使われる
・"実際の値"で評価された結果が"期待値"と等しい場合にはテストが成功
・等しくない場合は、AssertionFailedErrorというエラーが投げられる
・「テストの内容を表すメッセージ」は省略可だが、失敗したときに表示される
そのため、何をテストしているのか一目でわからないような場合は極力書くこと

■追加する行の実行結果について
実行結果ですが、テストが成功しています。
Calcクラスでは足し算を行うところで掛け算を行いましたが、成功してしまいました。
2*2と2+2は同じ4なのでバグを検出できなかったのです。
テストが成功する状態では何を直すべきかわからないし、
直したつもりででも直っているのか確認が取れません。
自動テストでは「前もってテストが失敗することを確認しておく」ことが重要です。

そこで「前もってテストが失敗することを確認しておく」ために、
次の一行を加えて再度実行してみます。

assertEquals(6, new Calc().add(2,4), "2 + 4 = 8");

//テストケースを追加
package test;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CalcTest {

    @Test
    void add() {
        assertEquals(4, new Calc().add(2,2), "2 + 2 = 4");
        assertEquals(6, new Calc().add(2,4), "2 + 4 = 8");
    }
}


■テストケースを追加した実行結果
今度はテストが成功しました。
足し算の代わりに掛け算を行ってしまっている不具合を、検出できるテストが書けたことになります。
あとはCalcクラスに移動して実装を修正していきます。
テストクラスからCalcクラスに移動するときは、
[Ctrl]+[Shift]+[T]を使うと瞬時に移動できます。
[Ctrl]+[Shift]+[T]は実装コードとテストコードを相互にジャンプするショートカットキーです。
a * bをa + bに修正します。
[Ctrl]+[Shift]+[F10]で実行したいところですが、
このショートカットキーは、
"今開いているファイルのテストやmainメソッドの実行をする"
コマンドのため使えません。(やっても反応なし)
今、開いているのは修正したCalcクラスであり、テストクラスではないです。
また、Calcクラスにはmainもないので実行できないというわけです。
しかし、テストクラスに戻らなくても「最後に実行した設定で再実行」できるショートカットキーがあります。
それが[Shift]+[F10]です。
先ほどショートカットキーから[Ctrl]を無しにしたバージョンですね。
実行するとテストは成功し完了となります。

■テストクラス名について
多くの場合、"テストクラス"は"テスト対象のクラス"と対になるので、
「テスト対象クラス名 Test」という名前で作成します。

■テストメソッドについて
テストメソッドはいくつ実装しても良いのでテスト対象メソッド一つに対して複数実装してもOKです。
確認する項目が多い場合や、確認する内容・性質が異なる場合は積極的にテストメソッドを分けます。
テストメソッドを分けるメリットは、実装中やデバッグ中に「何が動作して何が動作していないのか」が分かりやすくなります。

 

Junitのセットアップ(Maven)

前回「渡された年がサッカーワールドカップ開催年」であるかどうか、
を調べるメソッドを作成しました。
しかし、バグがあるので自動テストで修正するといったところで終わっています。
今回は続きとして修正行う予定でしたが、まずは自動テストの基礎固めを実施できればと思います。
具体的には、足し算を行うクラスのテストを行う流れを確認します。

まずは前提知識としてプログラムのテストについて学びます。

■プログラムのテストで確認していること
プログラムのテストは自動でも手動でも確認することは同じです。
何を確認しているのかというと、"用意した入力に対して期待通りの出力が得られるかどうか"です。
また、期待通りの出力とは以下が考えられます。
・メソッドの引数に用意した値を渡し、事前に割り出した期待される結果と一致するかどうか
・メソッド内でファイル出力やデータベースへの書き出しなどがあれば、その結果も期待通りであるか

これらを確認するプログラムを書きやすくするために生まれた、
Javaで最も標準的に使われるフレームワークJunit(らしい)です。
バージョンは現在5.x系が最新になります。

Junitのセットアップ
まず、足し算を行うクラスのテストを実施したいので
通常通りコードを作成します。

package test;
/**
 * 足し算
 */
public class Calc {
    /**
     * 渡された2つの値の足し算を行う
     * @param a 一つ目の値
     * @param b 二つ目の値
     * @return 足し算の結果
     * @since 2022/11/12
     */
    public int add(int a, int b) {
        return a * b;
    }
}

今回は練習として足し算を行うところで掛け算を行うという簡単なバグを仕込みました。
ここから、IntelliJ IDEAでJunitのテストの準備をしていきます。

IntelliJ IDEAでJunitのテスト開始手順

①Calc.javaを開いている状態で[Ctrl]+[Shift]+[T]を押下します。
ポップアップが表示されるので[新規テストの作成...]を選択します。
[テストの作成]というダイアログが開きます。
★補足説明
[Ctrl]+[Shift]+[T]は、実装コードとテストコードを相互にジャンプするショートカットキーです。
テストコードを作成していない場合は、[新規テストの作成...]から[テストの作成]で必要事項を埋めます。

②[テストの作成]では、テストライブラリに「Junit5」を選択します。
次の行には「Junit5ライブラリがモジュールに見つかりません」とあるので[修正]をクリックします。
続いて、「次のテストメソッドを生成」で左にあるチェックボックスにチェックを入れ[OK]をクリックします。
★補足説明
「Junit5ライブラリがモジュールに見つかりません」とは、プロジェクトのpom.xmlに、まだJunit5への依存が宣言されていませんよ~という意味です。
今回は依存を宣言するので[修正]をクリックすると、pom.xmlに「junit-jupiter」への依存が追加されているのがわかります。
jupiterはJnit5のコードネームのことらしいです。

③これでCalc.Test.javaが作成されます。
Junitのテストはクラスファイルとして表現され、src/test/java以下に配置します。
ここに自動テストのコードを記載していきます。
また、テストを行うクラスのことを「テストクラス」と呼びます。
★補足説明
テストクラス内の個別テストでは@Testアノテーションを付けた、
引数がなく戻り値がない(void)のメソッドとして実装します。
自動生成されたテストクラスでは@Testアノテーションがパッケージ名付きになっていることがあります。

package test;

import static org.junit.jupiter.api.Assertions.*;

class CalcTest {
//@Testアノテーションがパッケージ名付きになっている
    @org.junit.jupiter.api.Test
    void add() {
    }
}

気になる場合は[Alt]+[Enter]を押すと表示されるポップアップで
[修飾された名前指定をimportに変換]を選択してください。
パッケージをインポートして@Testのみにすることができます。

package test;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class CalcTest {
//パッケージをインポートして@Testのみになった
    @Test
    void add() {
    }
}

④テストの中身はまだ実装していませんが[Ctrl]+[Shift]+[F10]を押して実行してみます。

このショートカットキーを使用した時は、テキストカーソル位置で実行の動作が変わるので注意です。
・テストメソッド内にカーソル有⇒そのテストメソッドのみ実行
・テストメソッド外&テストクラス内にカーソル有⇒テストクラスすべてのテストメソッド実行

ショートカットキーを使用しない場合
・テストクラス横の[すべて実行]ボタンを押すと、テストクラス内全てのテストメソッドを実行。
・テストメソッド横の[一つ実行](▶)ボタンを押すと、そのテストメソッドのみ実行できます。

 

これで最低限の準備が整いました。
次回はテストケースの実装、実装コードの修正を行います。