web-dev-qa-db-fra.com

Configuration de MockMvc avec @WebMvcTest dans Spring Boot 1.4 MVC Testing

J'ai peu de code de travail pour configurer MockMVc de différentes manières avec le nouveau Spring Boot 1.4 @WebMvcTest. Je comprends l'approche standaloneSetup. Ce que je veux savoir, c'est la différence entre la configuration de MockMvc à WebApplicationContext et le câblage automatique MockMvc.

Extrait de code 1: MockMvc via WebApplicationContext Setup

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = ProductController.class)
public class ProductControllerTest {

private MockMvc mockMvc;

@Autowired
private WebApplicationContext webApplicationContext;

@MockBean
private ProductService productServiceMock;

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

@Test
public void testShowProduct() throws Exception {      

    Product product1 = new Product();
    /*Code to initialize product1*/

    when(productServiceMock.getProductById(1)).thenReturn(product1);

    MvcResult result = mockMvc.perform(get("/product/{id}/", 1))
            .andExpect(status().isOk())
            /*Other expectations*/
            .andReturn();
  }
}

Selon la documentation de l'API WebMvcTest, Par défaut, les tests annotés avec @WebMvcTest configureront également automatiquement Spring Security et MockMvc . Donc, je m'attendais à un code d'état 401 non autorisé ici, mais le test réussit avec un code d'état 200.

Ensuite, j'ai essayé le câblage automatique MockMvc, mais le test échoue avec le code d'état 401 non autorisé, sauf si j'ajoute @AutoConfigureMockMvc(secure=false) ou met à jour l'annotation @WebMvcTest Pour désactiver la sécurité:

@WebMvcTest(controllers = IndexController.class, secure = false)


Voici le code qui passe UNIQUEMENT APRÈS avoir désactivé explicitement la sécurité.

Extrait de code 2: MockMvc via le câblage automatique

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = ProductController.class)
@AutoConfigureMockMvc(secure=false)
public class ProductControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@MockBean
private ProductService productServiceMock;

@Test
public void testShowProduct() throws Exception {      

    Product product1 = new Product();
    /*Code to initialize product1*/

    when(productServiceMock.getProductById(1)).thenReturn(product1);

    MvcResult result = mockMvc.perform(get("/product/{id}/", 1))
            .andExpect(status().isOk())
            /*Other expectations*/
            .andReturn();
  }
}

Mes questions sont donc:

  1. Pourquoi l'extrait de code 1 n'a pas signalé d'erreur de code d'état 401 non autorisé lors du câblage automatique MockMvc. Réitérant également ce que dit le document officiel Par défaut, les tests annotés avec @WebMvcTest configureront également automatiquement Spring Security et MockMvc. Mais, dans ce cas, il apparaît @WebMvcTest N'a rien à voir avec la configuration automatique de Spring Security (car l'extrait de code 1 passe sans erreur 401). Cela revient finalement à la façon dont j'ai configuré le MockMvc. Ai-je raison ici?

  2. Quelles sont les différences/objectifs entre/des deux approches?

  3. En quoi la désactivation de la sécurité via @AutoConfigureMockMvc(secure=false) diffère de celle effectuée via @WebMvcTest(controllers = IndexController.class, secure = false). Laquelle est l'approche préférée ou quand (ou où) les utiliser?

16
user2693135

Je rencontre également un problème similaire. @WebMvcTest configure automatiquement Spring Security avec l'authentification de base, mais j'ai une classe WebSecurityConfig qui étend WebSecurityConfigurerAdapter. Dans cette classe, j'ai désactivé l'authentification de base et configuré la sécurité de la base de jetons. Cela signifie que la classe WebSecurityConfig n'est pas utilisée pour configurer Spring Security.

Pour résoudre le problème, j'ai ajouté @ContextConfiguration à ma classe de test unitaire et ajouté des simulations de dépendances de la classe WebSecurityConfig.

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = CategoryRestService.class)
@ContextConfiguration(classes={MjApplication.class, WebSecurityConfig.class})
public class CategoryRestServiceTest {

    @MockBean
    private CategoryRepository repository;

    @MockBean
    CurrentUserDetailsService currentUserDetailsService;

    @MockBean
    TokenAuthProvider tokenAuthProvider;

    @Autowired
    MockMvc mockMvc;

    private MediaType contentType = new    MediaType(MediaType.APPLICATION_JSON.getType(),
            MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));


    @Test
    public void getCategories() throws Exception {
        Category category1 = new Category();
        category1.setName("Test Category 1");
        category1.setId(1L);
        Category category2 = new Category();
        category2.setName("Test Category 2");
        category2.setId(2L);
        List<Category> categoryList = new ArrayList<Category>();
        categoryList.add(category1);
        categoryList.add(category2);
        given(this.repository.findAll())
        .willReturn(categoryList);
        mockMvc.perform(get("/public/rest/category"))
        .andExpect(status().isOk())
        .andExpect(content().contentType(contentType))
        .andExpect(jsonPath("$[0].id", is(1)))
        .andExpect(jsonPath("$[0].name", is("Test Category 1")))
        .andExpect(jsonPath("$[1].id", is(2)))
        .andExpect(jsonPath("$[1].name", is("Test Category 2")));
    }

}
9
UmitYeldan

Selon ce problème dans github

https://github.com/spring-projects/spring-boot/issues/5476

@WebMvcTest configure automatiquement par défaut, une authentification de base lorsque spring-security-test est dans le chemin de classe

Répondre à vos questions:

  1. Dans l'extrait de code 1, vous n'avez pas injecté le MockMvc dans votre classe de test, vous devez ajouter .apply (springSecurity ()) dans le générateur sur la méthode d'installation, afin que spring utilise la configuration de base (pas votre configuration de sécurité personnalisée si vous avez un)
  2. les deux approches font essentiellement la même chose, la différence est que la seconde est livrée avec l'authentification de base déjà dans le MockMvc, c'est pourquoi vous devez utiliser le secure = false
  3. De la documentation:

Par défaut, les tests annotés avec @WebMvcTest configurent également automatiquement Spring Security et MockMvc (incluent la prise en charge de HtmlUnit WebClient et Selenium WebDriver). Pour un contrôle plus fin de MockMVC, l'annotation @AutoConfigureMockMvc peut être utilisée.

6
Marco Prado

Je ne suis pas sûr que ce soit directement lié, mais il y a un bug exceptionnel où, si vous utilisez Spring Boot et @WebMvcTest, votre personnalisé @EnableWebSecurity La classe de configuration sera ignorée. Quelques solutions de contournement sont mentionnées dans le rapport de bogue. J'utilise:

@WebMvcTest(includeFilters = @Filter(classes = EnableWebSecurity.class))
3
djeikyb