此问题与this one有关。一旦发现问题,并成功应用了建议的解决方案,我将继续开发和重构代码,直到达到这一点为止。
如您在以下代码中看到的,我为我在控制器GetExchangeRate
中实例化的服务类定义了一个bean,因此我将其直接注入控制器中,避免注入其依赖项(ExchangeRateView
一个其实现的存储库使用JdbcTemplate
)。然后,我重构了测试,所以我不需要模拟ExchangeRateView
,而是模拟GetExchangeRate
。但是,这样做之后,我收到一个Application failed to start
错误,抱怨
com.fx.exchangerate.store.infrastructure.persistence.read.ExchangeRateJdbcView中的构造函数的参数0需要类型为'org.springframework.jdbc.core.JdbcTemplate'的bean
在我看来,即使我通过GetExchangeRate
注释模拟@MockBean
,它仍然试图从应用程序上下文中获取其依赖项,因为只要我将@MockBean ExchangeRateView exchangeRateView
添加到测试类中,它就可以正常运行。
所以我的问题是,@MockBean
真的是这样吗?模拟类是否仍然需要注入其依赖项?我在这里想念什么吗?
控制器:
@RestController
public class ExchangeRateStoreController {
private AddExchangeRateRequestAdapter addExchangeRateRequestAdapter;
private GetExchangeRate getExchangeRate;
private CommandBus commandBus;
@Autowired
public ExchangeRateStoreController(CommandBus commandBus, GetExchangeRate getExchangeRate) {
addExchangeRateRequestAdapter = new AddExchangeRateRequestAdapter();
this.commandBus = commandBus;
this.getExchangeRate = getExchangeRate;
}
@GetMapping
public ExchangeRate get(@RequestBody GetExchangeRateRequest getExchangeRateRequest) {
GetExchangeRateQuery query = new GetExchangeRateQuery(getExchangeRateRequest.from, getExchangeRateRequest.to, getExchangeRateRequest.date);
return getExchangeRate.execute(query);
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void create(@RequestBody AddExchangeRateRequest addExchangeRateRequest) {
commandBus.dispatch(addExchangeRateRequestAdapter.toCommand(addExchangeRateRequest));
}
}
测试:
@RunWith(SpringRunner.class)
@WebMvcTest(ExchangeRateStoreController.class)
public class ExchangeRateStoreControllerTest {
@Autowired
private MockMvc mvc;
@MockBean
ExchangeRateRepository exchangeRateRepository;
@MockBean
ExchangeRateDateValidator exchangeRateDateValidator;
@MockBean
GetExchangeRate getExchangeRate;
@Test
public void givenValidAddExchangeRateRequest_whenExecuted_thenItReturnsAnHttpCreatedResponse() throws Exception {
String validRequestBody = "{\"from\":\"EUR\",\"to\":\"USD\",\"amount\":1.2345,\"date\":\"2018-11-19\"}";
doNothing().when(exchangeRateDateValidator).validate(any());
doNothing().when(exchangeRateRepository).save(any());
mvc.perform(post("/").content(validRequestBody).contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isCreated());
}
@Test
public void givenGetExchangeRateRequestThatMatchesResults_whenExecuted_thenItReturnsOkResponseWithFoundExchangeRate() throws Exception {
when(getExchangeRate.execute(any(GetExchangeRateQuery.class))).thenReturn(anExchangeRate());
mvc.perform(get("/")
.content("{\"from\":\"EUR\",\"to\":\"USD\",\"date\":\"2018-11-19\"}")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
应用服务:
public class GetExchangeRate {
private ExchangeRateView view;
private Clock clock;
public GetExchangeRate(ExchangeRateView view, Clock clock) {
this.view = view;
this.clock = clock;
}
// More methods here
}
仓库实施类别:
@Repository
public class ExchangeRateJdbcView implements ExchangeRateView {
JdbcTemplate jdbcTemplate;
@Autowired
public ExchangeRateJdbcView(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
// More methods here
}
配置类:
@Configuration
public class ExchangeRateStoreConfig {
@Bean
@Autowired
public GetExchangeRate getExchangeRate(ExchangeRateView exchangeRateView, Clock clock) {
return new GetExchangeRate(exchangeRateView, clock);
}
@Bean
public Clock clock() {
return new Clock();
}
// More bean definitions
}
最佳答案
我终于设法找到了此问题的根本原因。我发现这是由于我在Spring Boot的主类中添加了@ComponentScan(basePackages = {"com.mycompany.myapp.infrastructure", "com.mycompany.myapp.application"} )
,因此@WebMvcTest
无法正常运行。
您可以在spring boot的文档中找到说明:
如果您使用测试注释来测试更具体的部分
应用程序,则应避免添加以下配置设置:
特定于主要方法的应用程序类中的特定区域。
@SpringBootApplication的基础组件扫描配置
定义排除过滤器,用于确保切片工作
预期。如果您在使用显式@ComponentScan指令
您的@SpringBootApplication注释类,请注意那些
过滤器将被禁用。如果使用切片,则应定义
他们再次。
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html