コントローラのテストを書きたいのですが。ここにテストスニペットがあります:
@RunWith(SpringRunner.class)
@WebMvcTest(WeatherStationController.class)
@ContextConfiguration(classes = MockConfig.class)
public class WeatherStationControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private IStationRepository stationRepository;
@Test
public void shouldReturnCorrectStation() throws Exception {
mockMvc.perform(get("/stations")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
コントローラコードスニペット:
@RestController
@RequestMapping(value = "stations")
public class WeatherStationController {
@Autowired
private WeatherStationService weatherService;
@RequestMapping(method = RequestMethod.GET)
public List<WeatherStation> getAllWeatherStations() {
return weatherService.getAllStations();
}
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public WeatherStation getWeatherStation(@PathVariable String id) {
return weatherService.getStation(id);
}
MockConfigクラス:
@Configuration
@ComponentScan(basePackages = "edu.lelyak.repository")
public class MockConfig {
//**************************** MOCK BEANS ******************************
@Bean
@Primary
public WeatherStationService weatherServiceMock() {
WeatherStationService mock = Mockito.mock(WeatherStationService.class);
return mock;
}
ここにエラースタックトレースがあります:
Java.lang.AssertionError: Status
Expected :200
Actual :404
私はここで何が悪いのかを得ることができます。
コントローラーのテストを修正する方法?
HTTPコード404 は、リクエストに対して(サーバー上で)リソースが見つからないことを意味します。これは、コントローラーがスプリングブートで表示されない(スキャンされていない)と考えられます。
簡単な解決策は、MockConfig
クラスの親パッケージをスキャンして、SpringがすべてのBeanを取得できるようにすることです。
_@ComponentScan(basePackages = "edu.lelyak") // assuming that's the parent package in your project
_
このアプローチが気に入らない場合は、コントローラのパッケージ名をbasePackages
に追加できます
_@ComponentScan(basePackages = {"edu.lelyak.controller","edu.lelyak.repository")
_
ところで、WeatherStationService
クラスでMockConfig
を手動で設定する必要はありません。SpringBootはモックを挿入し、各テストメソッドの後に自動的にリセットできます。テストクラス:
_@MockBean
private IStationRepository stationRepository;
_
一方、テストメソッドでweatherService.getAllStations()
を呼び出す前にget("/stations")
をモックする必要があります( 統合テスト を実行していないため)。 :
_List<WeatherStation> myList = ...;
//Add element(s) to your list
Mockito.when(stationService.getAllStations()).thenReturn(myList);
_
あなたはより多くを見つけることができます:
テストがうまくいかない理由はわかりません。しかし、私は私のために働く別の解決策を得ました。
@SpringBootTest
public class ControllerTest {
@Autowired
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(new TestController()).build();
}
@Test
public void shouldReturnCorrectStation() throws Exception {
mockMvc.perform(get("/stations")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
ここで私のために働いたコントローラーテストへの異なるアプローチがあります。
仮定:クラスWeatherStationService
は@SpringBootApplication
次に、以下のテストクラスが機能するはずです。
@RunWith(SpringRunner.class)
@SpringApplicationConfiguration(WeatherStationService.class)
@WebIntegrationTest
public class WeatherStationControllerTest {
@Autowired
private WebApplicationContext context;
MockMvc mockMvc;
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
@Test
public void shouldReturnCorrectStation() throws Exception {
mockMvc.perform(get("/stations")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk();
}
}
このテストセットアップにより、MockConfig
クラスは不要になります。
@ContextConfiguration(classes = MyConfig.class)
で外部構成クラスをインポートします
MyConfig
アノテーションを変更したとき@Configuration
から@TestConfiguration
正常に動作し始めました。
良い答えは見つかりませんでしたが、原因の1つを見つけることができました。
私はテストでRestControllerの@PreAuthorize
を使用していました。SpringBootTest
を使用する統合テストでOauth with this tip をモックすることができます。SpringBootTest
の場合、これもうまく機能しますが、SpringBootTest
を使用すると、単純なコントローラーテストを実行する必要のない他の多くのリソース(JPAなど)をロードします。
しかし@WebMvcTest
では、これは期待どおりに機能しません。 WithMockOAuth2Scope アノテーションを使用すれば、認証の問題による401エラーを回避できますが、その後、WebMvcTestは残りのエンドポイントを見つけることができず、404エラーコードを返します。
コントローラーの@PreAuthorize
を削除した後、WebMvcTest
を使用したテストに合格します。
私の場合、それは欠落している開始スラッシュについてでした/
最初の文字として/
およびRequestMapping value
パラメータの両方にMockHttpServletRequestBuilder post urlTemplate
を追加しました。