Openejb rest integration tests with exception mapp

2019-07-20 05:52发布

I'm writing some integration tests towards my jax-rs service where I have a set of exception mappers. So, when performing a given request I expect a certain response code based on the exception mapper. The problem is that I cannot get the exception mappers to be invoked when running in this environment.

My service which should throw a logicalexception in my test:

@Stateless
@Path("/baseCustomer")
public class BaseCustomerService {
    @EJB //this one gets mocked in the unittest
    private BaseCustomerManagerBean customerManager;

    @POST
    @Path("crud")
    @Consumes({MediaType.APPLICATION_XML})
    @Produces({MediaType.APPLICATION_XML, MediaType.TEXT_XML})
    public Hkunde createCustomer(Hkunde newCustomer) throws LogicalException {
        //throws exception according to mocking
        return customerManager.createCustomer(newCustomer); 
    }

And the exception mapper:

@Provider
public class LogicalExceptionMapper implements ExceptionMapper<LogicalException> {

    @Override
    public Response toResponse(LogicalException exception) {
        return Response.status(Response.Status.FORBIDDEN).build();
    }
} 

I set up my tests like this:

@Mock
private BaseCustomerManagerBean baseCustomerManager;
private HttpClient httpClient;
private BaseCustomerServiceClient client;

@Configuration
public Properties config() throws Exception {
    Properties properties = new Properties();
    properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.RemoteInitialContextFactory");
    properties.setProperty(OpenEjbContainer.OPENEJB_EMBEDDED_REMOTABLE, Boolean.TRUE.toString());

    properties.setProperty(DeploymentFilterable.CLASSPATH_INCLUDE, LogicalExceptionMapper.class.getName());
    properties.setProperty("openejb.jaxrs.providers.auto", "true");
    properties.setProperty("openejb.servicemanager.enabled", "true");
    return properties;
}

@MockInjector
public Class<?> mockitoInjector() {
    return MockitoInjector.class;
}

@Module
public EjbModule createModule() throws Exception {
    final StatelessBean bean = (StatelessBean) new StatelessBean(BaseCustomerService.class).localBean();
    bean.setRestService(true);

    final EjbJar ejbJar = new EjbJar();
    ejbJar.addEnterpriseBean(bean);

    final OpenejbJar openejbJar = new OpenejbJar();
    openejbJar.addEjbDeployment(new EjbDeployment(ejbJar.getEnterpriseBeans()[0]));

    EjbModule module = new EjbModule(ejbJar);
    module.setOpenejbJar(openejbJar);

    return module;
}
@Module
public Class[] exceptionMappers() {
    return new Class[]{LogicalExceptionMapper.class};
}

@Before
public void setup() {
    ServiceHost serviceHost = new ServiceHost("http://localhost:4204/BaseCustomerServiceTest");
    httpClient = new HttpClient(serviceHost);
    client = new BaseCustomerServiceClient(httpClient);
}

@Test
public void createCustomer_givenLogicalException_expectsLogicalException() throws LogicalException {
    Hkunde expected = new Hkunde(true);

    when(baseCustomerManager.createCustomer(expected)).thenThrow(new LogicalException("mock"));

    try {
        client.createCustomer(expected);
        fail("Expected LogicalException");
    } catch (LogicalException ex) {
    }

    verify(baseCustomerManager).createCustomer(expected);
}

So when I execute the test, my client will read the response code from the response and throw an exception based on this code.

The problem is that the exception mapper is never invoked, and I always receive a 500 internal server error, instead of the "forbidden" response. I'm guessing I need to add some more info when setting up the ejbjar or something like that.

Thanks!

1条回答
不美不萌又怎样
2楼-- · 2019-07-20 06:46

This example http://svn.apache.org/repos/asf/openejb/trunk/openejb/examples/rest-applicationcomposer/src/test/java/org/superbiz/composed/rest/GreetingServiceTest.java (via http://rmannibucau.wordpress.com/2012/09/13/use-mockito-with-openejb/ ;-)) shows exactly what you want.

Add the following after openejbJar.addEjbDeployment(... and it should work.

final Properties properties = openejbJar.getEjbDeployment().iterator().next().getProperties();
properties.setProperty("cxf.jaxrs.providers", LogicalExceptionMapper.class.getName());

Here is a minimal working example (using openejb-cxf-rs 4.5.0 and openejb-core 4.5.0):

import java.util.Properties;
import javax.ejb.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.openejb.OpenEjbContainer;
import org.apache.openejb.config.EjbModule;
import org.apache.openejb.jee.EjbJar;
import org.apache.openejb.jee.StatelessBean;
import org.apache.openejb.jee.oejb3.EjbDeployment;
import org.apache.openejb.jee.oejb3.OpenejbJar;
import org.apache.openejb.junit.ApplicationComposer;
import org.apache.openejb.junit.Configuration;
import org.apache.openejb.junit.Module;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(ApplicationComposer.class)
public class RestWithExceptionMapper {

    @Configuration
    public Properties configuration() {
        return new Properties() {
            {
                setProperty(OpenEjbContainer.OPENEJB_EMBEDDED_REMOTABLE, Boolean.TRUE.toString());
            }
        };
    }

    @Module
    public EjbModule app() {
        final StatelessBean bean = (StatelessBean) new StatelessBean(MyResource.class).localBean();
        bean.setRestService(true);
        final EjbJar ejbJar = new EjbJar();
        ejbJar.addEnterpriseBean(bean);
        final OpenejbJar openejbJar = new OpenejbJar();
        openejbJar.addEjbDeployment(new EjbDeployment(ejbJar.getEnterpriseBeans()[0]));
        final Properties properties = openejbJar.getEjbDeployment().iterator().next().getProperties();
        properties.setProperty("cxf.jaxrs.providers", MyExceptionMapper.class.getName());
        final EjbModule module = new EjbModule(ejbJar);
        module.setOpenejbJar(openejbJar);
        return module;
    }

    public static class FooException extends RuntimeException {
    }

    public static class MyExceptionMapper implements ExceptionMapper<FooException> {

        @Override
        public Response toResponse(final FooException t) {
            return Response.ok("Objection!").build();
        }
    }

    @Path(value = "/test")
    public static class MyResource {

        @GET
        @Path(value = "/throw")
        public String throwException() {
            throw new FooException();
        }
    }

    @Test
    public void checkServiceWasDeployed() {
        assertEquals("Objection!", WebClient.create("http://localhost:4204/RestWithExceptionMapper").path("/test/throw").get(String.class));
    }
}
查看更多
登录 后发表回答