I'm trying to figure out, what is the best way to Test the Security configuration of my Spring Boot App. My Goal is to have two Tests:
When starting my Research, all Tutorials that I found pointed to "MockMvc", but I wasn't able to write 2 Tests which worked this way. In almost all cases it seemed to me like Security was completely ignored (MockMvc returned 200 even without any User given).
Lets say I have the following setup, as a simple example:
Security config:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
}
}
Controller:
@RestController
public class TestController {
@GetMapping("/test")
public String getTest() {
return "hello";
}
}
Properties:
spring.security.user.name=testuser
spring.security.user.password=testpassword
I could successfully test this using "TestRestTemplate" like this:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class DemoApplicationTests {
@Autowired
private TestRestTemplate testRestTemplate;
@Test
void when_userIsValid_should_return200() throws Exception {
String res = testRestTemplate
.withBasicAuth("testuser", "testpassword")
.getForEntity("/test", String.class)
.getBody();
Assert.assertEquals("hello", res);
}
@Test
void when_userIsInvalid_should_return401() throws Exception {
HttpStatus res = testRestTemplate
.withBasicAuth("foo", "bar")
.getForEntity("/test", String.class)
.getStatusCode();
Assert.assertEquals(HttpStatus.UNAUTHORIZED, res);
}
}
So my question is: is this the "way to go"? If MockMvc is the Tool of choice, can you please provide a working example? I have tried like 30 solutions from Tutorials and Stackoverflow and none did work (either MockMvc null, Security was completely ignored, Controller Method wasn't detected anymore, and I'm just too stupid to make them work :/ )
Thank you in advance!
you can use WebMvcTest
to init only the Controller layer (it wont create/inject all other Spring beans defined a service/repository, etc..) but it is suitable (and quicker) when testing the Controller logic.
Here is an example
@AutoConfigureMockMvc
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = MainController.class)
public class ControllerTest {
@Autowired
private MockMvc mockMvc;
//@MockBean
//Service service; // mock service dependencies if needed
@Test
public void invalidCredentials() throws Exception {
this.mockMvc
.perform(get("/test").header(HttpHeaders.AUTHORIZATION,
"Basic " + Base64Utils.encodeToString("testuser:WRONGpassword".getBytes())))
.andExpect(status().isOk());
}
Thanks for your, help! ".andExpect(status().isOk())" should be ".andExpect(status().isUnauthorized())", but apart from that it works as expected, many thanks!