Andremoniy
Andremoniy

Reputation: 34900

How to mock Spring HandlerInterceptorAdapter in an integration test?

Say I have some FooInterceptor:

public class FooInterceptor extends HandlerInterceptorAdapter {
   // ...
}

Which is configured in the context:

 <mvc:interceptors>
     <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="my.package.FooInterceptor"/>
     </mvc:interceptor>
 </mvc:interceptors>

I am creating an integration test for some controller:

@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "/context.xml")
@ActiveProfiles("test")
public class SomeControllerIT {

    @Autowired
    private WebApplicationContext webApplicationContext;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders
                .webAppContextSetup(webApplicationContext)
                .apply(springSecurity())
                .build();
    }

    ...
}

I have tried to mock it via creating a custom configuration:

@Configuration
static class Config {

    @Bean
    @Primary
    public FooInterceptor getFooInterceptor() {
        return mock(FooInterceptor.class);
    }
}

But it doesn't seem to me to be working. The actual FooInterceptor is still produced and involved into the test.

How to properly mock it?

Upvotes: 4

Views: 9533

Answers (3)

Chetan Botre
Chetan Botre

Reputation: 321

You can go with the following as suggested by Luana FM in the previous answer. Also you'll need one line of mock code to return the response of interceptor as true in @BeforeEach block.

        @BeforeEach
        public void before() {
          MockitoAnnotations.initMocks(this);
          mockMvc = MockMvcBuilders
              .standaloneSetup(controller)
              .addInterceptors(interceptor)
              .build();
        when(interceptor.preHandle(Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(true);
    
        }

Upvotes: 3

Timothy Mugayi
Timothy Mugayi

Reputation: 1589

So I went ahead and wrote some code to solve the same question I had. Within our test case project, We can mock the interceptor by explicitly defining our own interceptor that extends HandlerInterceptorAdapter which will have mock logic mimicking our original interceptor

public class MockTenantInterceptor extends HandlerInterceptorAdapter

We can initialize the mock interceptor class without autowiring and proceed to register it within TestConfiguration class. Do make sure since we will have 2 configuration classes one for WebConfig and TestConfig to add the spring profile annotation that prevents your production interceptor from been invoked.

@Profile("test")
@TestConfiguration
@EnableJpaAuditing
public class TestConfig extends WebMvcConfigurerAdapter {


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        MockTenantInterceptor mockTenantInterceptor = new MockTenantInterceptor();
        registry.addInterceptor(mockTenantInterceptor);
    }
}

Edit: With Spring 5 / Spring Boot 2, extends WebMvcConfigurerAdapter has been deprecated in favor of implements WebMvcConfigurer and uses Java 8's new default methods for interfaces.

See https://www.baeldung.com/web-mvc-configurer-adapter-deprecated

Upvotes: 1

LFN
LFN

Reputation: 336

Isn't just injecting the interceptor an easier, cleaner way?

private MockMvc mockMvc;

@MockBean
private MyInterceptor interceptor;

@BeforeEach
public void before() {
  MockitoAnnotations.initMocks(this);
  mockMvc = MockMvcBuilders
      .standaloneSetup(controller)
      .addInterceptors(interceptor)
      .build();
}

Upvotes: 1

Related Questions