springspring-bootmockitojunit5mockmvc

MockMVC test - MockBean vs Mock issue with mockito whens?


I have the following mock mvc test class:

@SpringBootTest
@AutoConfigureMockMvc
class PersonControllerShould {

    @MockBean
    private PersonActivity personActivity;

    @MockBean
    private PersonMapper mapper;

    @Mock
    private MongoConfig mongoconfig;

    @Autowired
    private MockMvc mockMvc;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.openMocks(this);
    }
    
    // tests...
    
    }

Note that my activity and mapper classes are both spring managed @Components.

My MongoConfig class is as follows (not a component), hence why I have not created it as @MockBean (was giving me errors when trying this)

@ConfigurationProperties(prefix = "cosmosdb")
@ConstructorBinding
public class MongoConfig {

    // rest of code...
}

any mockito whens that I write on the MongoConfig do not seem to run, what is the issue here - is it possible to use both mockbeans and mocks in a mockmvc class?

Controller for reference:

@CrossOrigin(origins = "*")
@RestController
@RequestMapping(value = "/person")
public class PersonController {

    private final PersonActivity personActivity;
    private final PersonMapper mapper;
    private final MongoConfig mongoconfig;

    public PersonController(
            @Autowired PersonActivity personActivity;
            @Autowired PersonMapper mapper;
            @Autowired MongoConfig mongoconfig;
    ) {

        this.personActivity = personActivity;
        this.mapper = mapper;
        this.mongoconfig = mongoconfig;
    }
    
        // rest mappings 

    }

Solution

  • Don't mix @Mock (from Mockito) and @MockBean (from Spring Boot) annotations. Spring Boot will not see the Mockito mocks and you generally want your beans managed by Spring (and not have Mockito mess with them).

    @ConfigurationProperties are configuration data and it does not make sense to mock them. Properties of instances of these classes are bound to values of your application properties, so you can simply set the properties you need. To set properties for your test, add a new properties file in your test resources: src/test/resources/application.properties which defines the values used in your test.

    This will completely overwrite/replace all your regular application.properties settings. If you want to overwrite only some, you can leverage the fact that Spring runs your application (and tests) with the profile "default". Add a new file application-default.properties in your test resources and overwrite only the properties that require different values in your test.

    You may also run your test with a custom profile by annotating it with @ActiveProfiles. If you specify a different profile such as "integration", change the file name accordingly: application-integration.properties.

    Alternatively, overwrite the configuration values directly in your @SpringBootTest annotation:

    @SpringBootTest(
        properties = {
          "cosmosdb.url=url-to-be-used-in-your-test",
          "cosmosdb.user=testuser",
          "cosmosdb.password=testpassword"
        }
    )
    class PersonControllerShould {
      // ...
    }
    

    There's no need to have any when calls for your configuration and you can completely drop all Mockito-annotations-related code:

    @SpringBootTest/* (properties={...}) or application-test.properties */
    @AutoConfigureMockMvc
    class PersonControllerShould {
    
        @MockBean
        private PersonActivity personActivity;
    
        @MockBean
        private PersonMapper mapper;
    
        @Autowired
        private MockMvc mockMvc;
        
        // tests...
        
    }