SpringBoot @WebMvcTest and @MockBean not working as expected

beni0888 :

It seems that @WebMvcTest and @MockBean are not working as expected. Maybe I'm missing something... I have a controller with some dependencies I'm mocking with @MockBean, but the application fails to start because it cannot find another bean that I think should not be required in this case.

CONTROLLER:

@RestController
public class ExchangeRateStoreController {
    private AddExchangeRate addExchangeRate;
    private AddExchangeRateRequestAdapter addExchangeRateRequestAdapter;
    private GetExchangeRate getExchangeRate;
    private GetExchangeRateRequestAdapter getExchangeRateRequestAdapter;

    @Autowired
    public ExchangeRateStoreController(ExchangeRateRepository exchangeRateRepository, ExchangeRateDateValidator exchangeRateDateValidator, ExchangeRateView exchangeRateView) {
        addExchangeRate = new AddExchangeRate(exchangeRateRepository, exchangeRateDateValidator);
        addExchangeRateRequestAdapter = new AddExchangeRateRequestAdapter();
        getExchangeRate = new GetExchangeRate(exchangeRateView);
        getExchangeRateRequestAdapter = new GetExchangeRateRequestAdapter();
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public void create(@RequestBody AddExchangeRateRequest addExchangeRateRequest) {
        addExchangeRate.execute(addExchangeRateRequestAdapter.toCommand(addExchangeRateRequest));
    }
}

TEST:

@RunWith(SpringRunner.class)
@WebMvcTest(ExchangeRateStoreController.class)
public class ExchangeRateStoreControllerTest {

    @Autowired
    private MockMvc mvc;  
    @MockBean
    ExchangeRateRepository exchangeRateRepository;
    @MockBean
    ExchangeRateDateValidator exchangeRateDateValidator;
    @MockBean
    ExchangeRateView exchangeRateView;

    @Test
    public void givenValidExchangeRateCommand_whenCreate_thenOK() 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());
    }

APPLICATION:

@SpringBootApplication
@EnableJpaRepositories("com...exchangerate.store.infrastructure.persistence")
@EntityScan("com...exchangerate.store.infrastructure.persistence")
@ComponentScan(basePackages = {"com...exchangerate.store.infrastructure", "com...exchangerate.store.application"} )
public class ExchangeRateStoreApplication {
    public static void main(String[] args) {
        SpringApplication.run(ExchangeRateStoreApplication.class, args);
    }
}

And the error I get when run the test:

APPLICATION FAILED TO START


Description:

A component required a bean named 'entityManagerFactory' that could not be found.

Action:

Consider defining a bean named 'entityManagerFactory' in your configuration.

But, as you can see, entityManagerFactory is not a controller's dependency. So, why is the test trying to load this bean? I'm mocking all the controller dependencies, so I think it shouldn't do this.

Andy Wilkinson :

The problem's caused by your use of @EnableJpaRepositories on your application's main class. By placing it on the main class, you're indicating that JPA repositories must always be enabled, irrespective of which particular slice of functionality you're trying to test.

You can fix your problem by doing one of the following:

  • Move @EnableJpaRepositores and @EntityScan onto a separate JPA-specific configuration class
  • Remove @EnableJpaRepositories and @EntityScan and rely on the auto-configured defaults. For this to work, your repositories and entities will have to be in a sub-package of your main class's package.

There's some more information about this in Spring Boot's reference documentation where it says the following:

If you use a test annotation to test a more specific slice of your application, you should avoid adding configuration settings that are specific to a particular area on the main method’s application class.

In this particular case, the configuration setting that is specific to a particular area is @EnableJpaRepositories.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=74194&siteId=1