I am trying to unit test a controller class in my spring application. I am struggling a lot with this test. I want to test my my controller both in terms of method functionality and also authentication AND authorization.
Functionality is not an issue, but authorization and authentication are. Since I want to UNIT test I do not wish to annotate my test class with @SpringBootTest
as this loads the entire application context (if I am not mistaken). So I decided to go with @WebMvcTest
which adds security and my first issue with this is that it does not take roles into account. I have urls which are protected by roles and @WebMvcTest
doesn't seem to care about them. Also, after testing all my secured URLs I decided to test my public urls and I wrote my tests without any validation which resulted in a 401 error. After this I realized that all my other tests were passing by coincidence as in fact all urls happened to be protected and not the ones I have set in my security config class.
After reading online I found that I can include my security config class as part of the @ContextConfiguration
annotation. The only issue with this is that the tests don't run as the application context cannot be loaded. The reason being that the the security config class contains some variables annotated with @Autowired
. I started to include @MockBean
and the respective bean in my test class and one by one the errors started to change until finally the application context was loaded. I don't like this as none of the examples I found online had to do this, and it seems dirty to just have random variables inside my test just to please the config class.
I am really stuck and have been searching for hours but nothing has worked for me. I simply want to test my endpoints for functionality, authorization, and authentication using my config class and not some default class that Spring uses.
However, I have a question which I'm unsure about and maybe someone more experienced can answer me. Does testing authorization and authentication go outside of the scope of unit testing? Do I need to load the entire application context using @SpringBootTest
?
This is a snippet of my test class with the annotations and how I prepare MockMvc:
@RunWith(SpringRunner.class)
@WebMvcTest(value = MyController.class)
@ContextConfiguration(classes = {MyController.class,SecurityConfig.class})
public class MyControllerTest {
@Autowired
private MockMvc mockMvc;
}
My controller class is annotated with @Restcontroller
and none of the methods have @PreAuthorize
or @PostAuthorize
, they simply rely on the security config file. When testing manually (making calls to the API via POSTMAN) everything works as it should so I'm certain its a test configuration issue from my part.
This is my security config class (snippet):
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
@Order(3)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private ClassA classA;
@Autowired
private ClassB classB;
@Autowired
private ClassC classC;
...
.antMatchers("/public/**").permitAll()
}
This is the test that keeps returning 401 when I know it should return 200:
@Test
public void testGetIsProductionValue() throws Exception {
MvcResult result = mockMvc.perform(get("/public/production")
.param("production", "false"))
.andExpect(status().isOk())
.andReturn();
}