Spring Boot @MockBean estrange行为

时间:2018-11-29 18:59:06

标签: java spring unit-testing spring-mvc spring-boot

此问题与this one有关。一旦发现问题,并成功应用了建议的解决方案,我将继续开发和重构代码,直到达到这一点为止。

如下面的代码所示,我为在控制器GetExchangeRate中实例化的服务类定义了一个bean,因此我将其直接注入控制器中,避免注入其依赖项({{ 1}}存储库,其实现使用ExchangeRateView)。然后,我重构了测试,因此我不需要模拟JdbcTemplate,而是模拟ExchangeRateView。但是,这样做之后,我遇到GetExchangeRate错误,抱怨

  

com.fx.exchangerate.store.infrastructure.persistence.read.ExchangeRateJdbcView中的构造函数的参数0需要'org.springframework.jdbc.core.JdbcTemplate'类型的Bean

在我看来,即使我通过Application failed to start嘲笑GetExchangeRate,它仍在尝试从应用程序上下文中获取其依赖项,因为只要我添加{{1 }}转到测试类。

所以我的问题是@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
}

1 个答案:

答案 0 :(得分:0)

我终于设法找到了此问题的根本原因。我发现这是由于我在春季靴子的主类中添加了@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