maslick
maslick

Reputation: 3370

Create @MockBean with qualifier by annotating class?

In my Spring Boot test I'm using 2 mock beans with different qualifiers:

@RunWith(SpringRunner.class)
@SpringBootTest
class HohoTest {
    @MockBean @Qualifier("haha") IHaha ahaha;
    @MockBean @Qualifier("hoho") IHaha ohoho;
}

Since I'm not using these beans explicitly, I would rather move them away from the class body, as the @MockBean annotation is now repeatable:

@RunWith(SpringRunner.class)
@SpringBootTest
@MockBean(IHaha.class)
@MockBean(IHaha.class)
class HohoTest {}

However, I need to pass in a qualifier as well, since they have the same type. Any idea on how I can achieve that?

Upvotes: 23

Views: 31162

Answers (5)

Kevin Guanche Darias
Kevin Guanche Darias

Reputation: 701

This should now work

@SpringBootTest(
        classes = Some.class
)
@MockBean(name = BEAN_NAME, classes = TheBeanClass.class)
@MockBean(name = BEAN_NAME_2, classes = TheBeanClass.class)
class SomeTest {

    private final Some some;

    @Autowired
    SomeTest(Some some)  {
        this.some = some;
    }

}

Please note, if you need to use any of the mocked beans, you will have to put the @Qualifier in the constructor, for example

    private final TheBeanClass theBeanclass;
    private final Some some;

    @Autowired
    SomeTest(Some some, @Qualifier(BEAN_NAME) TheBeanClass theBeanClass)  {
        this.some = some;
        this.theBeanClass = theBeanClass;
    }

Upvotes: 2

Vladislav Kysliy
Vladislav Kysliy

Reputation: 3736

Because using annotation @Qualifier means choose bean by name, so you can set up a name for a mock with code like this:

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {JsonMapperConfig.class})
public class IntegrationFlowTest {

    @MockBean(name = "s3MessageRepository")
    private S3Repository s3MessageRepository;

// etc

Upvotes: 24

Arjun Sunil Kumar
Arjun Sunil Kumar

Reputation: 1838

I had a similar requirement of injecting mocked service beans with @Order annotation. I also needed to verify the invocation count of service functions. Below is my implementation. It might help someone.

import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ServiceNameTest {

  @Autowired private ServiceName serviceName;

  // Important: Used to reset interaction count of our static 
  // bean objects before every test.
  @Before
  public void reset_mockito_interactions() {
    Mockito.clearInvocations(MockServicesConfig.bean1);
    Mockito.clearInvocations(MockServicesConfig.bean2);
  }

  @Configuration
  public static class MockServicesConfig {

    public static InterfaceName bean1;
    public static InterfaceName bean2;

    @Bean
    @Order(1)
    public InterfaceName bean1() {
      bean1 = Mockito.mock(InterfaceName.class);
      // Common when() stubbing
      return bean1;
    }

    @Bean
    @Order(2)
    public InterfaceName vmpAdapter() {
      bean2 = Mockito.mock(InterfaceName.class);
      // Common when() stubbing
      return bean2;
    }
  }


  @Test
  public void test_functionName_mock_invocation1() {

    // Arrange --> Act --> Assert

    // nullify other functions custom when() stub.
    // updating this functions custom when() stub.

    verify(MockServicesConfig.bean1, times(1)).functionName("");
  }

  @Test
  public void test_functionName_mock_invocation2() {

    // Arrange --> Act --> Assert

    // nullify other functions custom when() stub.
    // updating this functions custom when() stub.

    verify(MockServicesConfig.bean1, times(1)).functionName("");
  }


}

Upvotes: 1

oberlies
oberlies

Reputation: 11723

If it is okay to move the mock definition completely out of the test class, you could also create the mocks in a separate @Configuration class:

@Configuration
public class MockConfiguration
{
    @Bean @Qualifier("haha")
    public IHaha ahaha() {
        return Mockito.mock(IHaha.class);
    }
    @Bean @Qualifier("hoho")
    public IHaha ohoho() {
        return Mockito.mock(IHaha.class);
    }
}

Upvotes: 6

Sam Brannen
Sam Brannen

Reputation: 31227

When declaring @MockBean at the class level, there is currently no support for providing a qualifier.

If you would like to have such support, I suggest you request it in the Spring Boot issue tracker.

Otherwise, you will need to continue declaring @MockBean on fields alongside @Qualifier.

Upvotes: 6

Related Questions