先日、JUnitを1月程触る機会があり、色々と勉強したので忘れないように備忘録を残しておくことにした。
JUnit歴1か月弱なので、おかしなことを書いているかもしれない。おかしなところを見つけた場合はスルーするかそっと優しくご指摘ください。
環境
JDK1.8
Spring-boot 2.4.2
JUnit 5
テストコードの書き方
ビジネスロジックのテスト
まずはソースコードをドン!
public class Calc {
public int add(int num1, int num2) {
return num1 + num2;
}
}
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class CalcTest {
Calc c = new Calc();
@Test
@DisplayName("add test")
public void addTest() {
// 実際の値
int actual = c.add(1, 1);
// 期待値
int expected = 2;
assertThat(actual, is(expected));
}
}
足し算を行うCalc#addと、そのテストコードCalcTest#addTest。
命名
色々な宗派があると思うが、テスト対象のメソッド名+Test
が多い気がする。
@Testアノテーション
このメソッドはテストコードですよ、の印。
お作法的に書いてしまってるのが本音なので、もう少し深堀して理解したいところ。
@DisplayNameアノテーション
Eclipse等でJUnit実行したときに、ここで指定した名前がテスト結果に表示される。
省略可能で、省略時はメソッド名がそのまま表示される。
assertThat
assertThat(T actual, Matcher<? super T> matcher)
でテストを実行する。
actualが実際値で、matherが期待値。ここが一致すればテスト成功、不一致ならテスト失敗。
assertThatのほかに、assertEquals, assertTrue, assertFalseなど様々あるが、個人的にはassertThatが一番使いやすく感じた。色々調べた中での個人的assertThatのメリットとしては
- assert that actual is expected と英文として自然な形でコーディングできるため、可読性が高い
- 第二引数
Matcher<? super T> matcher
で使えるメソッドが豊富 → https://qiita.com/opengl-8080/items/e57dab6e1fa5940850a3
です。
参考:https://qiita.com/YNYS2020/items/8090048d3f540455b699
Controllerのテスト
SpringのControllerのテストはassertThatではなく、MockMvcを使う。
@Controller
public class HogeController {
@RequestMapping(value = "/top")
public String top() {
return "top";
}
}
@SpringBootTest(classes = HogeController.class)
public class HogeControllerTest {
/** MockMvc */
private MockMvc mockMvc;
/** WebApplicationContext */
@Autowired
private WebApplicationContext webApplicationContext;
/**
* 前処理
*/
@BeforeEach
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
}
@Test
public void topTest() throws Exception {
mockMvc.perform(get("/top"))
.andExpect(status().isOk())
.andExpect(view().name("top"));
}
}
mockMvc.perform
の後ろにテストしたい条件をつらつらと記載していく寸法。
わりと直感的にできてわかりやすい。
get("/top")
の後ろにもいろいろメソッドチェーンで条件を付与できる(Cookieやリクエストパラメタ/ヘッダなど)
Formバリデーションのテスト
以下がとても参考になった。
これ以上の説明を書くことは私には無理なので、リンクを引用しておく。
https://qiita.com/akane_kato/items/8bfc6fa9bf1f7518e515
staticメソッドのmock化
staticメソッドのmock化は少し工夫が必要です。
try (final var localDateTime = Mockito.mockStatic(LocalDateTime.class)) {
localDateTime.when(LocalDateTime::now).thenReturn(LocalDateTime.of(1970, 1, 1, 0, 0, 0)));
// write test code ...
}
例えばLocalDateTime.now()
の値を固定したい場合、上記のように記述する。
Mockito.mockStatic
で対象メソッドのクラスをモック化し、try-with-resourceで宣言する。
引数を持つstaticメソッドの場合は以下のようにメソッド参照を使う。
@MockBean
private WebApplicationContext mockWac;
@Test
public void test() throws Exception {
try (var webapplicationContextUtilsMock = Mockito.mockStatic(WebApplicationContextUtils.class)) {
webapplicationContextUtilsMock.when(() -> WebApplicationContextUtils.getWebApplicationContext(Mockito.any())).thenReturn(mockWac);
doReturn(new Hoge()).when(mockWac).getBean("hoge");
}
// write test code ...
}