Search code examples
javaspring-bootjunitcucumber

Mocking object in Cucumber


I'm trying to test my project using BDD and therefore im using Cucumber. The problem is, that when I want to test ProductController i can't properly mock my ProductService and i get NullPointerException - my service is null. Below is code for my steps.

@SpringBootTest
@AutoConfigureMockMvc
public class ProductControllerSteps {
    
    long productId;
    Product product;
    
    @Autowired
    MockMvc mockMvc;
    
    @MockBean
    ProductService service;
    
    private ResultActions result;
    
    @Given("user has a valid product id")
    public void user_has_a_valid_product_id() {
        productId = 1L;
        product = new Product();
        product.setId(productId);
        Mockito.when(service.getProductById(productId)).thenReturn(product);
    }
    @When("user makes GET request")
    public void user_makes_get_request() throws Exception {
        result  = mockMvc.perform(MockMvcRequestBuilders.get("/api/products/"+productId).accept(MediaType.APPLICATION_JSON_VALUE)).andDo(print());
        
    }
    @Then("system returns product data")
    public void system_returns_product_data() throws Exception {
        result.andExpect(status().is2xxSuccessful());
    }
    
}

As i seen in cucumber guides i also created such a classes for cucumber configuration:

@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("features")
@ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "pretty")
public class RunCucumberTest {
}

and also:

@CucumberContextConfiguration
@SpringBootTest
@AutoConfigureMockMvc
@ContextConfiguration(classes = ShopApiApplication.class)
public class SpringGlue{
}

I'm trying to mock my service with mockito, yet every kind of configuration does not work and result in null pointer exception, i dont have any idea how to make it work.


Solution

  • The class annotated with @CucumberContextConfiguration is used to configure the Spring application context using Springs Test Context Framework Manager. This includes setting up mocks through the MockitoTestExecutionListener.

    Declaring a mock bean can be done with an annoatation on the SpringGlue class. It is also possible to declare mocks by adding fields to the class and annotating those.

    @CucumberContextConfiguration
    @SpringBootTest
    @AutoConfigureMockMvc
    @ContextConfiguration(classes = ShopApiApplication.class)
    @MockBean(ProductService.class)
    public class SpringGlue {
    }
    

    And because of that the MockBean annotation on the ProductControllerSteps does not do anything. This class should look like:

    public class ProductControllerSteps {
        
        ...
        
        @Autowired
        MockMvc mockMvc;
        
        @Autowired
        ProductService service;
    

    The autowired service will be a mock so you can use Mockito.when(...) as normal.

    Note: If you have multiple features they'll all use the same context configuration. If you need multiple configurations, multiple runners are needed with different glue configurations.