2013-08-16 7 views
9

Questa domanda è la risposta a una domanda precedente Specify Custom Application Context.Recupera un bean gestito da un contenitore JerseyTest con jersey-spring3

Stiamo migrando alcuni dei nostri servizi dati da Jersey 1.x utilizzando jersey-spring a Jersey 2.x utilizzando jersey-spring3.

Abbiamo alcune classi di test che ereditano da JerseyTest. Alcune di queste classi utilizzano file applicationContext.xml personalizzati non specificati nel file web.xml.

Per scopi di derisione dell'oggetto, prendiamo in giro alcuni componenti nelle risorse di Jersey.

In Jersey 1.x potremmo prendere in giro oggetti nel file di contesto applicazione

<bean id="mockBean" class="org.easymock.EasyMock" 
    factory-method="createStrictMock" autowire="byName"> 
    <constructor-arg index="0" value="com.xxx.xxx.ClassToMock" /> 
</bean> 

e recuperare queste istanze deriso come segue

ClassToMock obj = (ClassToMock)ContextLoader 
    .getCurrentWebApplicationContext() 
    .getAutowireCapableBeanFactory() 
    .getBean("mockBean"); 

Come può lo stesso essere raggiunto con Jersey 2. x usando jersey-spring3?

Ho passato il API docs, user guides e alcuni dei sources ma non sono riuscito a trovare una risposta.

Grazie.

EDIT:

Useremo i fagioli deriso all'interno delle nostre risorse JAX-RS. Abbiamo interfacce di servizio che sono @Autowired nelle nostre risorse.

ad es.

@Path(ProductResource.RESOURCE_PATH) 
@Component 
@Scope("prototype") 
public class ProductResource 
extends GenericResource<Product, BaseModel> { 

    /* 
    * Members 
    */ 

    public static final String RESOURCE_PATH = "product/"; 

    @Autowired 
    protected ProductService productService; 

    ... 

Vogliamo prendere in giro e impostare le aspettative su questi servizi.

ad es.

<bean id="productService" class="org.easymock.EasyMock" 
    factory-method="createStrictMock"> 
    <constructor-arg index="0" 
     value="com.xxx.xxx.service.ProductService" /> 
</bean> 
+0

Puoi illustrarlo su un esempio? (Come/Quando/Dove stai usando il bean di mocked? È all'interno di una risorsa JAX-RS?) Hai bisogno esattamente di 'WebApplicationContext' o di qualsiasi' ApplicationContext' è sufficiente? –

+0

O "WebApplicationContext" o "ApplicationContext" andrebbero bene. Quale mai ci darebbe un puntatore al bean che è stato iniettato nelle risorse JAX-RS. –

risposta

8

Nota: Io non sono un esperto di primavera e ritengo che questo sia piuttosto un work-around che un approccio consigliato. Spero che qualcuno possa trovare una soluzione migliore.

Non si può ottenere un'istanza ApplicationContext chiamando ContextLoader#getCurrentWebApplicationContext() perché Jersey 2.x runtime è di default inizializzata al di fuori di un contenitore di servlet quando si utilizza Jersey Framework Test (JerseyTest) per le prove di unità/E2E.

In questo caso è necessario utilizzare un po 'di lavoro-around per ottenere un ApplicationContext implementando un'interfaccia ApplicationContextAware nel pacchetto di prova:

public class ApplicationContextUtils implements ApplicationContextAware { 

    private static ApplicationContext applicationContext; 

    public static ApplicationContext getApplicationContext() { 
     return applicationContext; 
    } 

    @Override 
    public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException { 
     ApplicationContextUtils.applicationContext = applicationContext; 
    } 
} 

Una volta che avete questa classe, non dimenticate di parlarne nell'applicazione context descrittore:

... 
<bean class="org.glassfish.jersey.examples.helloworld.spring.ApplicationContextUtils" /> 
... 

E lo si può utilizzare nei test:

public class JerseySpringResourceTest extends JerseyTest { 

    // ... Configure ... 

    @Before 
    public void mockUp() throws Exception { 
     // ApplicationContext is ready in your @Before methods ... 
     assertThat(ApplicationContextUtils.getApplicationContext(), notNullValue()); 
    } 

    @Test 
    public void testJerseyResource() { 
     // ... as well as in your test methods. 
     assertThat(ApplicationContextUtils.getApplicationContext(), notNullValue()); 
    } 
} 

Nota: Se si desidera distribuire l'applicazione per un contenitore di servlet ed eseguire le (JerseyTest) le prove contro di esso, consultare il Jersey Test Framework capitolo della Guida Utenti (soprattutto External container sezione).

+0

Grazie per il feedback. Lo farò un test appena posso. Solo una domanda. Non dovrebbe 'this.applicationContext = applicationContext;' in 'setApplicationContext' piuttosto essere' ApplicationContextUtils.applicationContext = applicationContext; 'vedere come applicationContext è un campo statico. –

+0

Sì, corretto. Grazie. –

+1

Si potrebbe anche usare l'annotazione '@Component' su ApplicationContextUtils (assicurandosi che si trovi all'interno di un pacchetto che è scansionato dal componente), lasciando così la necessità di dichiarare esplicitamente il bean. –

1

Per gli utenti Jersey 2.x, ecco cosa ha funzionato per me:

public class AccountResourceTest extends JerseyTest { 

    private ApplicationContext context; 

    private BeanA beanA; 

    private BeanB beanB; 

    public AccountResourceTest() throws TestContainerException { 
     super(); 

     beanA = context.getBean(BeanA.class); 
     beanB = context.getBean(BeanB.class); 
    } 

    @Override 
    protected Application configure() { 
     context = new AnnotationConfigApplicationContext(SpringConfiguration.class); 
     final ResourceConfig config = new JerseyConfiguration().property("contextConfig", context); 
     return config; 
    } 

    @Override 
    protected void configureClient(final ClientConfig config) { 
     config.register(JacksonJsonProvider.class); 
    } 

    ... 
} 

Questo mi permette di utilizzare JavaConfig per i miei test Jersey, e accedere ai fagioli nel contesto pure. Ecco il link al punto in cui ho avuto l'idea: http://geowarin.github.io/spring-boot/jersey/2014/01/31/a-simple-spring-boot-and-jersey-application.html

1

con la maglia la versione 2.4.x, la classe JerseyConfiguration non esiste più ed è stato sostituito da ResourceConfig, che non comprende la proprietàcontextConfig. Ecco la mia soluzione:

package ch.vd.test; 

import java.net.URI; 

import javax.ws.rs.core.Application; 

import org.glassfish.hk2.api.ServiceLocator; 
import org.glassfish.jersey.server.ApplicationHandler; 
import org.glassfish.jersey.server.ResourceConfig; 
import org.glassfish.jersey.test.JerseyTest; 
import org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory; 
import org.glassfish.jersey.test.spi.TestContainer; 
import org.glassfish.jersey.test.spi.TestContainerException; 
import org.glassfish.jersey.test.spi.TestContainerFactory; 
import org.junit.Test; 
import org.springframework.context.ApplicationContext; 

public class ExampleTest extends JerseyTest { 

    private ServiceLocator serviceLocator; 

    @Override 
    public void setUp() throws Exception { 
     super.setUp(); 
     final ApplicationContext context = serviceLocator.getService(ApplicationContext.class, "SpringContext"); 
     final Object bean = context.getBean("someBean"); 
    } 

    @Override 
    protected Application configure() { 
     final ResourceConfig config = new ResourceConfig(RestResources.class); 
     config.property("contextConfigLocation", "classpath:example-context.xml"); 
     return config; 
    } 

    @Override 
    protected TestContainerFactory getTestContainerFactory() throws TestContainerException { 
     return new GrizzlyTestContainerFactory() { 
      @Override 
      public TestContainer create(URI uri, ApplicationHandler appHandler) throws IllegalArgumentException { 
       serviceLocator = appHandler.getServiceLocator(); 
       return super.create(uri, appHandler); 
      } 
     }; 
    } 

    @Test 
    public void testStuff() throws Exception { 
     ... 
    } 
} 
3

È possibile inserire la classe di test nel contesto di Jersey se non si dispone di alcuna obiezione.

Ad esempio:

@Override 
protected Application configure() { 
    final TestJerseyApplication application = new TestJerseyApplication(); 

    final Map<String, Object> properties = new HashMap<>(); 
    properties.put("contextConfigLocation", "classpath:test-spring-context.xml"); 
    application.setProperties(properties); 

    application.register(this); 
    return application; 
} 

Dopo che l'annotazione @Autowired lavorerà per voi.

+0

Ah, possiamo dire a Jersey quale file di contesto Spring personalizzato cercare tramite "contextConfigLocation", invece del nome predefinito "applicationContext.xml". – jediz

Problemi correlati