Skip to content

Instantly share code, notes, and snippets.

@orekyuu
Last active October 31, 2021 14:40
Show Gist options
  • Save orekyuu/cb0a23b38327a19b8a48dc2a5b4e7964 to your computer and use it in GitHub Desktop.
Save orekyuu/cb0a23b38327a19b8a48dc2a5b4e7964 to your computer and use it in GitHub Desktop.
Nestedを使ったControllerのテスト
package net.orekyuu.controllertestdemo;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.result.StatusResultMatchers;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
// SpringBootのMockMvcのテスト
// 辛みとしては、mockMvcの呼び出しが複雑だったりすると同じようなコードをテストケースごとに何度も書かないといけないのでノイジー
// 与えるパラメータが違う場合、レスポンスが変わるテストをしたいのでそこだけ抜き出して観点を目立つようにしたい
public class SumControllerTest {
@SpringBootTest
@AutoConfigureMockMvc
static abstract class SumControllerTestBase implements TestContext<MvcResult> {
@Autowired
MockMvc mockMvc;
@Override
public MvcResult subject() throws Exception {
return mockMvc.perform(post("/sum").param("a", String.valueOf(paramA())).param("b", String.valueOf(paramB())))
.andExpect(status(MockMvcResultMatchers.status()))
.andReturn();
}
abstract ResultMatcher status(StatusResultMatchers s);
public String paramA() {
return "1";
}
public String paramB() {
return "2";
}
@Override
public void it(MvcResult result) throws Exception {
}
}
@Nested
class Succeeded extends SumControllerTestBase {
@Override
ResultMatcher status(StatusResultMatchers s) {
return s.isOk();
}
@Override
public void it(MvcResult result) throws Exception {
assertThat(result.getResponse().getContentAsString()).isEqualTo("3");
}
}
@Nested
class MinusSucceeded extends SumControllerTestBase {
@Override
ResultMatcher status(StatusResultMatchers s) {
return s.isOk();
}
@Override
public String paramA() {
return "5";
}
@Override
public String paramB() {
return "-10";
}
@Override
public void it(MvcResult result) throws Exception {
assertThat(result.getResponse().getContentAsString()).isEqualTo("-5");
}
}
@Nested
class BadRequestIfStringParam extends SumControllerTestBase {
@Override
ResultMatcher status(StatusResultMatchers s) {
return s.isBadRequest();
}
@Override
public String paramA() {
return "text";
}
}
}
package net.orekyuu.controllertestdemo;
import org.junit.jupiter.api.Test;
// Testのベース
public interface TestContext<R> {
// テスト対象の呼び出し
R subject() throws Exception;
// 結果のassertをする場所
void it(R result) throws Exception;
// テストの実行
@Test
default void doTest() throws Exception {
R subject = subject();
it(subject);
}
}
package net.orekyuu.controllertestdemo;
import org.junit.jupiter.api.Nested;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
// UserRepositoryなどの単純なクラスのテスト
// 辛みとしては、与えるパラメータの組み立てが大変な場合組み立て部分が冗長になってノイジー
// 組み立て部分の差分と、テストの観点を目立たせたい
class UserRepositoryTest {
static abstract class FindAdultUserTestBase implements TestContext<List<User>> {
// テスト時する前にDBに入れておきたいUserのList
List<User> users() {
return List.of();
}
// クエリを発行した結果とれる件数
public int resultSize() {
return 0;
}
@Override
public List<User> subject() throws Exception {
UserRepository repository = new UserRepository();
// setup
users().forEach(repository::insert);
return repository.findAdultUser(); // 今回のテスト対象は成人したユーザーを見つけてくるメソッド
}
@Override
public void it(List<User> result) throws Exception {
// findAdultUserを呼び出した結果、resultSizeと一致するかをテストしたい
assertThat(result).hasSize(resultSize());
}
}
@Nested
class IfEmpty extends FindAdultUserTestBase {
@Override
List<User> users() {
return List.of();
}
@Override
public int resultSize() {
return 0;
}
}
@Nested
class OnlyNonAdult extends FindAdultUserTestBase {
@Override
List<User> users() {
return List.of(new User(1, 10));
}
@Override
public int resultSize() {
return 0;
}
}
@Nested
class OnlyAdult extends FindAdultUserTestBase {
@Override
List<User> users() {
return List.of(new User(1, 22));
}
@Override
public int resultSize() {
return 1;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment