Ce qui est nécessaire pour faire mockMVC test d'un filtre init routine?
J'ai mis en application les CORS du filtre, qui fonctionne lorsque le code est exécuté sur le serveur:
/*
* Copyright 2013 BrandsEye (http://www.brandseye.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.energyos.espi.datacustodian.web.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;
/**
* Adds CORS headers to requests to enable cross-domain access.
*/
@Component
public class CORSFilter implements Filter {
private final Log logger = LogFactory.getLog(getClass());
private final Map<String, String> optionsHeaders = new LinkedHashMap<String, String>();
private Pattern allowOriginRegex;
private String allowOrigin;
private String exposeHeaders;
public void init(FilterConfig cfg) throws ServletException {
String regex = cfg.getInitParameter("allow.origin.regex");
if (regex != null) {
allowOriginRegex = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
} else {
optionsHeaders.put("Access-Control-Allow-Origin", "*");
}
optionsHeaders.put("Access-Control-Allow-Headers", "Origin, Authorization, Accept, Content-Type");
optionsHeaders.put("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
optionsHeaders.put("Access-Control-Max-Age", "1800");
for (Enumeration<String> i = cfg.getInitParameterNames(); i.hasMoreElements(); ) {
String name = i.nextElement();
if (name.startsWith("header:")) {
optionsHeaders.put(name.substring(7), cfg.getInitParameter(name));
}
}
//maintained for backward compatibility on how to set allowOrigin if not
//using a regex
allowOrigin = optionsHeaders.get("Access-Control-Allow-Origin");
//since all methods now go through checkOrigin() to apply the Access-Control-Allow-Origin
//header, and that header should have a single value of the requesting Origin since
//Access-Control-Allow-Credentials is always true, we remove it from the options headers
optionsHeaders.remove("Access-Control-Allow-Origin");
exposeHeaders = cfg.getInitParameter("expose.headers");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
if (logger.isDebugEnabled()) {
logger.debug("CORSFilter processing: Checking for Cross Origin pre-flight OPTIONS message");
}
if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse)response;
if ("OPTIONS".equals(req.getMethod())) {
allowOrigin = "*"; //%%%%% Test force of allowOrigin
if (checkOrigin(req, resp)) {
for (Map.Entry<String, String> e : optionsHeaders.entrySet()) {
resp.addHeader(e.getKey(), e.getValue());
}
//We need to return here since we don't want the chain to further process
//a preflight request since this can lead to unexpected processing of the preflighted
//request or a 40x - Response Code
return;
}
} else if (checkOrigin(req, resp)) {
if (exposeHeaders != null) {
resp.addHeader("Access-Control-Expose-Headers", exposeHeaders);
}
}
}
filterChain.doFilter(request, response);
}
private boolean checkOrigin(HttpServletRequest req, HttpServletResponse resp) {
String origin = req.getHeader("Origin");
if (origin == null) {
//no origin; per W3C specification, terminate further processing for both pre-flight and actual requests
return false;
}
boolean matches = false;
//check if using regex to match origin
if (allowOriginRegex != null) {
matches = allowOriginRegex.matcher(origin).matches();
} else if (allowOrigin != null) {
matches = allowOrigin.equals("*") || allowOrigin.equals(origin);
}
if (matches) {
//Activate next two lines and comment out third line if Credential Support is required
// resp.addHeader("Access-Control-Allow-Origin", origin);
// resp.addHeader("Access-Control-Allow-Credentials", "true");
resp.addHeader("Access-Control-Allow-Origin", "*");
return true;
} else {
return false;
}
}
public void destroy() {
}
}
La suite de test JUnit utilise mockMVC mais échoue, car le CORSFilter "init" la logique n'est pas exécuté (prouvé par breakpointing le test JUnit):
package org.energyos.espi.datacustodian.integration.web.filters;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.servlet.FilterConfig;
import org.energyos.espi.datacustodian.web.filter.CORSFilter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("/spring/test-context.xml")
@Profile("test")
public class CORSFilterTests {
private final Log logger = LogFactory.getLog(getClass());
@Autowired
private CORSFilter filter;
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = webAppContextSetup(this.wac)
.addFilters(filter).build();
}
@Test
public void optionsResponse_hasCorrectFilters() throws Exception {
RequestBuilder requestBuilder = MockMvcRequestBuilders.options("/DataCustodian/oauth/token")
.header("Origin", "foobar")
.header("Access-Control-Allow-Origin", "*");
MvcResult result = mockMvc.perform(requestBuilder)
.andExpect(header().string("Access-Control-Allow-Origin", is("*")))
.andExpect(header().string("Access-Control-Allow-Methods", is("GET, POST, PUT, DELETE, OPTIONS")))
.andExpect(header().string("Access-Control-Allow-Headers", is("origin, authorization, accept, content-type")))
.andExpect(header().string("Access-Control-Max-Age", is("1800")))
.andReturn();
}
}
}
J'ai passé en revue la documentation disponible sur internet, ce qui semble impliquer l' ".addfilter(filtre). élément de la mockMVC @Avant l'article devrait être de l'exécution de la CORSFilter init routine. Cependant, ce n'est clairement PAS passe.
Des suggestions ou des recommandations serait grandement apprécié, car je suis vraiment coincé compréhension de la façon d'obtenir le "init" de routine testé à l'aide de la mockMVC capacité.
OriginalL'auteur Donald F. Coffin | 2013-12-28
Vous devez vous connecter pour publier un commentaire.
Le Spring MVC suite de Test n'est pas destiné à tester la configuration du conteneur, il est destiné à tester votre MVC (
@Controller
et d'autres mappings) de configuration .Filter#init(ServletConfig)
est gérée par le conteneur de la méthode.Si vous avez vraiment besoin de tester, vous pouvez vous moquer de qui trop
Vous êtes les bienvenus. Si cela répond à votre question, envisager d'accepter.
Je n'étais pas en mesure de mettre en œuvre le correctif que vous avez suggéré, mais tiens à accepter votre réponse, mais je ne suis pas sûr de savoir comment le faire (désolé c'est mon premier poste). J'ai fait le CORSFilter vérifier l'origine de "JUnit_Test" et ensuite fournir les données les CORSFilter init routine lorsque le filtre est chargé par le serveur. J'aimerais comprendre la solution que vous avez suggéré, mais depuis qu'il fait essentiellement le même que le code que j'ai ajouté, j'ai pris un raccourci pour gagner du temps.
J'ai pris trop de votre question. Vous pouvez faux objets avec des bibliothèques comme Mockito. Ces moqué objets présentent le comportement que vous souhaitez. Par exemple, un
Filter
aurait besoin de tout le conteneur de servlet, mais pas avec des simulacres. Découvrez les exemples dans le lien, et d'autres à travers le net. Si vous souhaitez accepter ma réponse, vous pouvez cocher la case située à côté de ma réponse du score.OriginalL'auteur
Après beaucoup de tests, voici ce que nous avons adoptée:
@RestController
utilisation MockMvc.TestRestTemplate
.Avec MockMvc,
addFilter(Filter)
n'a pas abouti à l'exécution du filtre. La solution avecTestRestTemplate
est plus primitive, mais tous les Filtres configurés dans votre application/bibliothèques sont exécutées. Exemple:OriginalL'auteur
Si vous voulez un vrai test de l'unité à la place d'un test d'intégration, vous pouvez également prendre un coup d'oeil à
org.springframework.mock.web.MockServletConfig
disponible à partir deorg.springframework:spring-test
artefact mavenVous pouvez configurer les paramètres de config sur le simulacre de l'objet. Il y a aussi des mocks pour HttpServletRequest, HttpServletResponse et FilterChain
OriginalL'auteur
Pour un
Spring Boot
application, si@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
est utilisé puis filtrer.init() est appelée automatiquement. si@SpringBootTest
est utilisé avec les paramètres par défaut puis filtrer.init() doit être appelé manuellement.OriginalL'auteur