Jersey - How to mock service

前端 未结 2 992
你的背包
你的背包 2020-11-27 19:31

I am using \"Jersey Test Framework\" for unit testing my webservice.

Here is my resource class :

import javax.ws.rs.GET;
import javax.ws.rs.Path;
imp         


        
2条回答
  •  半阙折子戏
    2020-11-27 20:06

    See Update below: You don't need a Factory


    If you are using Jersey 2, one solution would be to use Custom Injection and Lifecycle Management feature (with HK2 - which comes with the Jersey dist). Also required would be a Mocking framework of course. I'm going to use Mockito.

    First create a Factory with mocked instance:

    public static interface GreetingService {
        public String getGreeting(String name);
    }
    
    public static class MockGreetingServiceFactory 
                                         implements Factory {
        @Override
        public GreetingService provide() {
            final GreetingService mockedService
                    = Mockito.mock(GreetingService.class);
            Mockito.when(mockedService.getGreeting(Mockito.anyString()))
                    .thenAnswer(new Answer() {
                        @Override
                        public String answer(InvocationOnMock invocation) 
                                                          throws Throwable {
                            String name = (String)invocation.getArguments()[0];
                            return "Hello " + name;
                        }
    
                    });
            return mockedService;
        }
    
        @Override
        public void dispose(GreetingService t) {}
    }
    

    Then use the AbstractBinder to bind the factory to the interface/service class, and register the binder. (It's all described in the link above):

    @Override
    public Application configure() {
        AbstractBinder binder = new AbstractBinder() {
            @Override
            protected void configure() {
                bindFactory(MockGreetingServiceFactory.class)
                                   .to(GreetingService.class);
            }
        };
        ResourceConfig config = new ResourceConfig(GreetingResource.class);
        config.register(binder);
        return config;
    }
    

    Seems like a lot, but it's just an option. I'm not too familiar with the test framework, or if it has an mocking capabilities for injection.

    Here is the full test:

    import javax.inject.Inject;
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.QueryParam;
    import javax.ws.rs.client.Client;
    import javax.ws.rs.client.ClientBuilder;
    import javax.ws.rs.core.Application;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;
    import org.glassfish.hk2.api.Factory;
    import org.glassfish.hk2.utilities.binding.AbstractBinder;
    import org.glassfish.jersey.server.ResourceConfig;
    import org.glassfish.jersey.test.JerseyTest;
    import org.junit.Assert;
    import org.junit.Test;
    import org.mockito.Mockito;
    import org.mockito.invocation.InvocationOnMock;
    import org.mockito.stubbing.Answer;
    
    public class ServiceMockingTest extends JerseyTest {
    
        @Path("/greeting")
        public static class GreetingResource {
    
            @Inject
            private GreetingService greetingService;
    
            @GET
            @Produces(MediaType.TEXT_PLAIN)
            public String getGreeting(@QueryParam("name") String name) {
                return greetingService.getGreeting(name);
            }
        }
    
        public static interface GreetingService {
            public String getGreeting(String name);
        }
        
        public static class MockGreetingServiceFactory 
                                      implements Factory {
            @Override
            public GreetingService provide() {
                final GreetingService mockedService
                        = Mockito.mock(GreetingService.class);
                Mockito.when(mockedService.getGreeting(Mockito.anyString()))
                        .thenAnswer(new Answer() {
                            @Override
                            public String answer(InvocationOnMock invocation) 
                                                           throws Throwable {
                                String name = (String)invocation.getArguments()[0];
                                return "Hello " + name;
                            }
    
                        });
                return mockedService;
            }
    
            @Override
            public void dispose(GreetingService t) {}
        }
    
        @Override
        public Application configure() {
            AbstractBinder binder = new AbstractBinder() {
                @Override
                protected void configure() {
                    bindFactory(MockGreetingServiceFactory.class)
                            .to(GreetingService.class);
                }
            };
            ResourceConfig config = new ResourceConfig(GreetingResource.class);
            config.register(binder);
            return config;
        }
        
        @Test
        public void testMockedGreetingService() {
            Client client = ClientBuilder.newClient();
            Response response = client.target("http://localhost:9998/greeting")
                    .queryParam("name", "peeskillet")
                    .request(MediaType.TEXT_PLAIN).get();
            Assert.assertEquals(200, response.getStatus());
            
            String msg = response.readEntity(String.class);
            Assert.assertEquals("Hello peeskillet", msg);
            System.out.println("Message: " + msg);
            
            response.close();
            client.close();
           
        }
    }
    

    Dependencies for this test:

    
        org.glassfish.jersey.test-framework.providers
        jersey-test-framework-provider-grizzly2
        2.13
    
    
        org.mockito
        mockito-all
        1.9.0
    
    

    UPDATE

    So in most cases, you really don't need a Factory. You can simply bind the mock instance with its contract:

    @Mock
    private Service service;
    
    @Override
    public ResourceConfig configure() {
        MockitoAnnotations.initMocks(this);
        return new ResourceConfig()
            .register(MyResource.class)
            .register(new AbstractBinder() {
                @Override
                protected configure() {
                    bind(service).to(Service.class);
                }
            });
    }
    
    @Test
    public void test() {
        when(service.getSomething()).thenReturn("Something");
        // test
    }
    

    Much simpler!

提交回复
热议问题