Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SpringBoot @WebMvcTest and @MockBean not working as expected

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.

like image 820
beni0888 Avatar asked Nov 28 '18 17:11

beni0888


People also ask

What is mockbean annotation in Spring Boot?

1. @MockBean annotation It allow to mock a class or an interface and to record and verify behaviors on it. It can be used as a class level annotation or on fields in either @Configuration classes, or test classes that are @RunWith the SpringRunner.

Should I use @webmvctest with Spring Boot?

With @WebMvcTest, Spring Boot provides everything we need to build web controller tests, but for the tests to be meaningful, we need to remember to cover all of the responsibilities. Otherwise, we may be in for ugly surprises at runtime. The example code from this article is available on github.

What is mockmvc in Spring Boot?

Spring boot MockMVC example Learn to use Spring MockMVC to perform integration testing of Spring webmvc controllers. MockMVC class is part of Spring MVC test framework which helps in testing the controllers explicitly starting a Servlet container.

What are the advantages of using @mockbean from Spring Boot?

It is fast and favors the isolation of the tested component. If the test needs to rely on the Spring Boot container and we want also to add or mock one of the container beans then @MockBean from Spring Boot is preferred way to add mocks. 3. @MockBean in unit testing


1 Answers

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.

like image 57
Andy Wilkinson Avatar answered Oct 20 '22 07:10

Andy Wilkinson