2010-12-02 2 views
8

Je commence par jersey et j'essaie de faire travailler le freemarker avec TDD. Je souhaite créer un ViewProcessor pour mes modèles, mais ne parviens pas à injecter le contexte de servlet dans la classe.L'injection de contexte de servlet échoue lors de l'utilisation du framework de test jersey

Voici le code de classe:

@Provider 
public class myProcessor implements ViewProcessor<Template> { 

    [...] 

    @Context 
    public ServletContext myContext; 

    [...] 

freemarkerConfiguration.setTemplateLoader(
     new WebappTemplateLoader(myContext, 
      myContext.getInitParameter("freemarker.template.path"))); 

    [...] 
    } 

Et voici le code de test:

public class myProcessorTest extends JerseyTest { 

    public static myProcessor mp; 

    public myProcessorTest() throws Exception{ 
     super(new WebAppDescriptor.Builder("com.domain").build()); 
    } 

    @Test 
    public void firstTest(){ 
     mp = new myProcessor(); 
     String path = new String("test.ftl"); 
     Template template = mp.resolve(path); 
     assertNotNull(template); 
    } 
} 

J'utilise maven avec des dépendances comme suit:

<dependency> 
    <groupId>com.sun.jersey.jersey-test-framework</groupId> 
    <artifactId>jersey-test-framework-grizzly</artifactId> 
    <version>1.5-SNAPSHOT</version> 
    <scope>test</scope> 
</dependency> 

Mon code fonctionne bien quand je me déploie sur mon serveur de jetée local. Mais si je veux tester le code dans mon IDE, il n'a pas réussi à injecter le contexte de servlet (@Context): myContext est null quand je lance le test:/

Je pense que je manque quelque chose, mais je suis débutant complet avec le monde de servlet.

Répondre

0

Il y a plusieurs façons de le faire. Retirez le constructeur et mettre en œuvre une méthode configure() comme ceci:

public class myProcessorTest extends JerseyTest { 

    public static myProcessor mp; 

    @Override 
    protected AppDescriptor configure() { 
    return new WebAppDescriptor.Builder("com.domain") 
     .contextParam("contextConfigLocation", "classpath:/applicationContext.xml") 
     .contextPath("/").servletClass(SpringServlet.class) 
     .contextListenerClass(ContextLoaderListener.class) 
     .requestListenerClass(RequestContextListener.class) 
     .build(); 
    } 

ou bien vous pouvez annoter votre test avec le contexte du printemps:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("classpath:applicationContext.xml") 
public class MyProcessorTest extends JerseyTest { 

    public static myProcessor mp; 
0

Il y a une solution à ce problème qui ne nécessite pas printemps, en supposant que vous utilisez le fournisseur de framework de test Grizzy2 par défaut/standard. Selon this answer le fournisseur de cadre jersey-test-framework-provider-grizzly2 n'utilise pas un environnement de servlet dans la construction du contexte d'application. Vos symptômes résultent de l'absence d'instance ServletContext à injecter.

La solution consiste à fournir vous-même le conteneur de test pour les tests unitaires. Tout d'abord, modifier vos dépendances:

<!--<dependency> 
    <groupId>org.glassfish.jersey.test-framework.providers</groupId> 
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId> 
    <version>2.25</version> 
    <scope>test</scope> 
</dependency>--> 
<dependency> 
    <groupId>org.glassfish.jersey.test-framework</groupId> 
    <artifactId>jersey-test-framework-core</artifactId> 
    <version>2.25</version> 
</dependency> 
<dependency> 
    <groupId>org.glassfish.jersey.containers</groupId> 
    <artifactId>jersey-container-grizzly2-servlet</artifactId> 
    <version>2.25</version> 
</dependency> 

Ensuite, modifiez votre test pour fournir un conteneur de servlet Grizzy:

@Override 
protected TestContainerFactory getTestContainerFactory() throws TestContainerException { 
    return (final URI baseUri, final DeploymentContext deploymentContext) -> 
    new TestContainer() { 
    private HttpServer server = null; 

    @Override 
    public ClientConfig getClientConfig() { 
     return null; 
    } 

    @Override 
    public URI getBaseUri() { 
     return baseUri; 
    } 

    @Override 
    public void start() { 
     try { 
     this.server = GrizzlyWebContainerFactory.create(baseUri, Collections 
      .singletonMap("jersey.config.server.provider.packages", "<your-package-name>")); 
     } catch (final ProcessingException | IOException cause) { 
     throw new TestContainerException(cause); 
     } 
    } 

    @Override 
    public void stop() { 
     this.server.shutdownNow(); 
    } 
    }; 
} 

Je suppose que vous allez utiliser dans plusieurs tests unitaires, donc il peut être sage d'étendre JerseyTest afin que cette configuration commune puisse être effectuée automatiquement. En outre, il peut être utile de vérifier org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory pour voir s'il existe des fonctionnalités fournies par le conteneur de test que vous souhaitez émuler/conserver. L'exemple fourni devrait pouvoir être déposé dans votre test pour au moins confirmer qu'il s'agit d'un correctif.

EDIT: Dans ma propre implémentation, j'ai demandé la possibilité de fournir un ResourceConfig lors de la génération du serveur. Je soupçonne que ceci est susceptible d'être le cas courant pour d'autres utilisateurs de Jersey Test Framework. Un exemple de travail de TestContainerFactory proposé suit.

import java.io.IOException; 
import java.net.URI; 
import java.util.logging.Level; 
import java.util.logging.Logger; 

import javax.servlet.ServletContext; 
import javax.ws.rs.ProcessingException; 
import javax.ws.rs.core.UriBuilder; 

import org.glassfish.grizzly.http.server.HttpServer; 
import org.glassfish.grizzly.servlet.WebappContext; 
import org.glassfish.hk2.utilities.binding.AbstractBinder; 
import org.glassfish.jersey.client.ClientConfig; 
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory; 
import org.glassfish.jersey.test.DeploymentContext; 
import org.glassfish.jersey.test.spi.TestContainer; 
import org.glassfish.jersey.test.spi.TestContainerException; 
import org.glassfish.jersey.test.spi.TestContainerFactory; 
import org.glassfish.jersey.test.spi.TestHelper; 


public class RestTestContainerFactory implements TestContainerFactory {  
    public static class RestTestContainer implements TestContainer { 
    private static final Logger LOGGER = Logger.getLogger(RestTestContainer.class.getName()); 

    private URI baseUri = null; 
    private final HttpServer server; 

    public RestTestContainer(final URI baseUri, final DeploymentContext context) { 
     this.baseUri = UriBuilder.fromUri(baseUri).path(context.getContextPath()).build(); 
     if(LOGGER.isLoggable(Level.INFO)) { 
     LOGGER.info("Creating RestRestContainer configured at the base URI "+TestHelper.zeroPortToAvailablePort(baseUri)); 
     } 

     try { 
     final WebappContext webContext = new WebappContext("TestContext", context.getContextPath()); 
     context.getResourceConfig() 
       .register(new AbstractBinder() { 
       @Override 
       protected void configure() { 
        bind(webContext).to(ServletContext.class); 
       } 
       }); 
     this.server = GrizzlyHttpServerFactory.createHttpServer(this.baseUri, context.getResourceConfig(), false); 
     webContext.deploy(this.server); 

     } catch (final ProcessingException cause) { 
     throw new TestContainerException(cause); 
     } 
    } 

    @Override 
    public ClientConfig getClientConfig() { 
     return null; 
    } 

    @Override 
    public URI getBaseUri() { 
     return baseUri; 
    } 

    @Override 
    public void start() { 
     if(server.isStarted()) { 
     LOGGER.warning("Ignoring start request - RestTestContainer is already started"); 
     } else { 
     LOGGER.fine("Starting RestTestContainer..."); 
     try { 
      server.start(); 
      if(baseUri.getPort() == 0) { 
      baseUri = UriBuilder.fromUri(baseUri) 
       .port(server.getListener("grizzly").getPort()) 
       .build(); 
      LOGGER.info("Started GrizzlyTestContainer at the base URI "+baseUri); 
      } 
     } 
     catch(final ProcessingException | IOException cause) { 
      throw new TestContainerException(cause); 
     } 
     } 
    } 

    @Override 
    public void stop() { 
     if(server.isStarted()) { 
     LOGGER.fine("Stopping RestTestContainer..."); 
     server.shutdownNow(); 
     } else { 
     LOGGER.warning("Ignoring stop request - RestTestContainer is already stopped"); 
     } 
    } 
    } 

    @Override 
    public TestContainer create(final URI baseUri, final DeploymentContext context) { 
    return new RestTestContainer(baseUri,context); 
    } 
} 

Frustrant, GrizzlyWebContainerFactory Grizzly fournira un contexte de servlet, mais pas configurer avec une configuration de ressources. Inversement, GrizzlyHttpServerFactory va configurer une application avec un ResourceConfig, mais ne fournira pas de contexte Web.

Nous pouvons contourner ce problème en créant le WebappContext (étend ServletContext) manuellement, la configuration, puis l'injecter dans la configuration des ressources au moyen d'un AbstractBinder.

Questions connexes