I'd like to test a Spring Boot
Rest controller, which is secured using Spring security
, and use mocks inside it. I have tried with Mockito, but I think any mocking tool should do the trick.
To enable Spring security in my tests, I first did as follow:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Main.class)
@TestPropertySource(value="classpath:application-test.properties")
@WebAppConfiguration
@ContextConfiguration
public class MyTest{
protected MockMvc mockMvc;
@Autowired
private WebApplicationContext wac;
@Before
public void setUp(){
mockMvc = MockMvcBuilders
.webAppContextSetup(wac)
.apply(SecurityMockMvcConfigurers.springSecurity())
.build();
}
@Test
public void doTheTest(){
mockMvc.perform(post("/user/register")
.with(SecurityMockMvcRequestPostProcessors.csrf())
.content(someContent()));
}
}
Until there, it works well.
After this step, I wished to add mocks to test my secured controller in isolation.
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Main.class)
@TestPropertySource(value="classpath:application-test.properties")
@WebAppConfiguration
@ContextConfiguration
public class MyTest{
protected MockMvc mockMvc;
@Mock
private Myservice serviceInjectedInController;
@InjectMocks
private MyController myController;
@Autowired
private WebApplicationContext wac;
@Before
public void setUp(){
mockMvc = MockMvcBuilders
.webAppContextSetup(wac)
.apply(SecurityMockMvcConfigurers.springSecurity())
.build();
}
@Test
public void doTheTest(){
mockMvc.perform(post("/user/register")
.with(SecurityMockMvcRequestPostProcessors.csrf())
.content(someContent()));
}
}
Unfortunately, the mocked service is not injected in the controller, as there is nothing relating the MockMVC and the Mocks, so the mocks are not injected in the controller.
So I tried changing the configuration of the MockMVC, as follows:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Main.class)
@TestPropertySource(value="classpath:application-test.properties")
@WebAppConfiguration
@ContextConfiguration
public class MyTest{
protected MockMvc mockMvc;
@Mock
private Myservice serviceInjectedInController;
@InjectMocks
private MyController myController;
@Before
public void setUp(){
mockMvc = MockMvcBuilders
.standAloneSetup(myController)
.apply(SecurityMockMvcConfigurers.springSecurity())
.build();
}
@Test
public void doTheTest(){
mockMvc.perform(post("/user/register")
.with(SecurityMockMvcRequestPostProcessors.csrf())
.content(someContent()));
}
}
But in this case, I have another issue. Spring security is complaining about the configuration:
java.lang.IllegalStateException: springSecurityFilterChain cannot be null. Ensure a Bean with the name springSecurityFilterChain implementing Filter is present or inject the Filter to be used.
I have no other idea to make security and mocking. Any idea? Or should I do another way?
Thanks.
MockMvc provides support for Spring MVC testing. It encapsulates all web application beans and makes them available for testing. We'll initialize the mockMvc object in the @BeforeEach annotated method, so that we don't have to initialize it inside every test.
MockMvc is defined as a main entry point for server-side Spring MVC testing. Tests with MockMvc lie somewhere between between unit and integration tests.
MockMVC class is part of Spring MVC test framework which helps in testing the controllers explicitly starting a Servlet container. In this MockMVC tutorial, we will use it along with Spring boot's WebMvcTest class to execute Junit testcases which tests REST controller methods written for Spring boot 2 hateoas example.
By default the integration looks for a bean with the name of "springSecurityFilterChain". In the example that was provided, a standalone setup is being used which means MockMvc
will not be aware of the WebApplicationContext
provided within the test and thus not be able to look up the "springSecurityFilterChain" bean.
The easiest way to resolve this is to use something like this:
MockMvc mockMvc = MockMvcBuilders
// replace standaloneSetup with line below
.webAppContextSetup(wac)
.alwaysDo(print())
.apply(SecurityMockMvcConfigurers.springSecurity())
.build();
If you really want to use a standaloneSetup (doesn't really make sense since you already have a WebApplicationContext), you can explicitly provide the springSecurityFilterChain using:
@Autowired
FilterChainProxy springSecurityFilterChain;
@Before
public void startMocks(){
controller = wac.getBean(RecipesController.class);
MockMvc mockMvc = MockMvcBuilders
.standaloneSetup(controller)
.alwaysDo(print())
.apply(SecurityMockMvcConfigurers.springSecurity(springSecurityFilterChain))
.build();
MockitoAnnotations.initMocks(this);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With