泽西岛 – 如何模拟服务

我正在使用“Jersey测试框架”对我的网络服务进行unit testing。

这是我的资源类:

import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; // The Java class will be hosted at the URI path "/helloworld" @Path("/helloworld") public class class HelloWorldResource { private SomeService service; @GET @Produces("text/plain") public String getClichedMessage() { // Return some cliched textual content String responseFromSomeService = service.getSomething(); return responseFromSomeService; } } 

如何在unit testing中模拟SomeService?

以下是我使用Jersey 2.20,Spring 4.1.4 RELEASE,Mockito 1.10.8和TestNG 6.8.8的方法。

 @Test public class CasesResourceTest extends JerseyTestNg.ContainerPerMethodTest { @Mock private CaseService caseService; @Mock private CaseConverter caseConverter; @Mock private CaseRepository caseRepository; private CasesResource casesResource; @Override protected Application configure() { MockitoAnnotations.initMocks(this); casesResource = new CasesResource(); AbstractBinder binder = new AbstractBinder() { @Override protected void configure() { bindFactory(new InstanceFactory(caseConverter)).to(CaseConverter.class); bindFactory(new InstanceFactory(caseService)).to(CaseService.class); } }; return new ResourceConfig() .register(binder) .register(casesResource) .property("contextConfigLocation", "solve-scm-rest/test-context.xml"); } public void getAllCases() throws Exception { when(caseService.getAll()).thenReturn(Lists.newArrayList(new solve.scm.domain.Case())); when(caseConverter.convertToApi(any(solve.scm.domain.Case.class))).thenReturn(new Case()); Collection cases = target("/cases").request().get(new GenericType>(){}); verify(caseService, times(1)).getAll(); verify(caseConverter, times(1)).convertToApi(any(solve.scm.domain.Case.class)); assertThat(cases).hasSize(1); } } 

您还需要这个类使上面的绑定代码更容易:

 public class InstanceFactory implements Factory { private T instance; public InstanceFactory(T instance) { this.instance = instance; } @Override public void dispose(T t) { } @Override public T provide() { return instance; } } 

编辑为pr。 请求。 这是我的test-context.xml的内容:

    

事实certificate,我的test-context.xml没有实例化任何bean也没有扫描任何包,事实上,它根本不做任何事情。 我想我只是把它放在那里以防万一我需要它。

请参阅下面的更新:您不需要Factory


如果您使用的是Jersey 2,那么一种解决方案就是使用自定义注入和生命周期管理function(使用HK2 – 与Jersey dist一起使用)。 当然,还需要一个Mocking框架。 我打算用Mockito。

首先用模拟实例创建一个Factory:

 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) {} } 

然后使用AbstractBinder将工厂绑定到接口/服务类,并注册绑定器。 (这些都在上面的链接中描述):

 @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; } 

看起来很多,但它只是一个选项。 我不太熟悉测试框架,或者它是否具有注入的模拟function。

这是完整的测试:

 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(); } } 

此测试的依赖关系:

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

UPDATE

所以在大多数情况下,你真的不需要Factory 。 您可以简单地将mock实例与其契约绑定:

 @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 } 

更简单!