Spring Bootを始めたばかりなのですが、よくわからんことがあったのでメモ。解決していません。私がSpring BootのDIよくわかってないだけだと思う。
あらまし
ServiceをモックせずにControllerのユニットテスト(JUnit4)を実行したらMockMVCのレスポンスボディが空になってしまった。対象のSpring Bootのバージョンは1.5系で、テンプレートエンジンはThymeleafを使用。
テスト対象のController
@Controller
@RequestMapping("/")
public class DemoController {
@Autowired
DemoService service;
@GetMapping("hello")
public String demo (Model model) {
model.addAttribute("message", service.getMessage());
return "hello";
}
}
Service
@Service
public class DemoService {
public String getMessage() {
return "message.";
}
}
失敗するテスト
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoControllerTests {
@Autowired
private DemoController controller;
private MockMvc mockMvc;
@Before
public void setup() {
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
@Test
public void helloにアクセスする() throws Exception {
mockMvc.perform(get("/hello"))
.andExpect(status().isOk()) // ここは通る
.andExpect(content().string(containsString("message"))); // contentが空文字になってしまって通らない
} // 実際のアプリケーションで /hello にアクセスすると期待通りの挙動になる
}
ViewResolver?が動いてないっぽい?ControllerだけインジェクトしてもViewResolver?までインジェクトできないのかもしれない。
ServiceがMockBeanでいいならGetting Started · Testing the Web Layer通りに書けばいいが、今回はMockを使わずに通しの動作をテストしたい。
回避策として書いて、かつ期待通りには動作したテスト
とりあえずWebApplicationContextをAutowiredでインジェクトしてみたら動いた。
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoControllerTests {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
@Test
public void helloにアクセスする() throws Exception {
mockMvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("message"))); // 期待通り通った
}
}
※動かないパターンのレスポンスボディが空文字になる理由が理解できてないので、このコードはあくまで回避策。