English 中文(简体)
如何使用mockito测试REST服务?
原标题:How to use mockito for testing a REST service?

我是Java单元测试的新手,听说Mockito框架非常适合测试。

我已经开发了一个REST服务器(CRUD方法),现在我想测试它,但我不知道如何测试?

更重要的是,我不知道这个测试程序应该如何开始。我的服务器应该在localhost上工作,然后对该url进行调用(例如localhost:8888)?

这是我迄今为止所尝试的,但我非常确定这不是正确的方法。

    @Test
    public void testInitialize() {
        RESTfulGeneric rest = mock(RESTfulGeneric.class);

        ResponseBuilder builder = Response.status(Response.Status.OK);

        builder = Response.status(Response.Status.OK).entity(
                "Your schema was succesfully created!");

        when(rest.initialize(DatabaseSchema)).thenReturn(builder.build());

        String result = rest.initialize(DatabaseSchema).getEntity().toString();

        System.out.println("Here: " + result);

        assertEquals("Your schema was succesfully created!", result);

    }

下面是初始化方法的代码。

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/initialize")
    public Response initialize(String DatabaseSchema) {

        /** Set the LogLevel to Info, severe, warning and info will be written */
        LOGGER.setLevel(Level.INFO);

        ResponseBuilder builder = Response.status(Response.Status.OK);

        LOGGER.info("POST/initialize - Initialize the " + user.getUserEmail()
                + " namespace with a database schema.");

        /** Get a handle on the datastore itself */
        DatastoreService datastore = DatastoreServiceFactory
                .getDatastoreService();


        datastore.put(dbSchema);

        builder = Response.status(Response.Status.OK).entity(
                "Your schema was succesfully created!");
        /** Send response */
        return builder.build();
    }

在这个测试用例中,我想向服务器发送一个Json字符串(POST)。如果一切顺利,那么服务器应该回复“您的架构已成功创建!”。

有人能帮帮我吗?

最佳回答

好的。因此,该方法的约定如下:将输入字符串解析为JSON,如果无效,则返回BAD_REQUEST。如果它有效,在数据存储中创建一个具有各种属性(你知道它们)的实体,并发送回OK

您需要验证此合同是否通过该方法履行。

Mockito在哪里帮忙?好吧,如果你在没有Mockito的情况下测试这个方法,你需要一个真正的DataStoreService,并且你需要验证实体是否在这个真正的DataStoreService

Mockito可以通过模拟对DataStoreService的依赖来提供帮助:您可以创建一个DataStareService的模拟,并在测试中调用initialize()

为此,您需要能够将DataStoreService注入到被测对象中。它可以像以下方式重构对象一样简单:

public class MyRestService {
    private DataStoreService dataStoreService;

    // constructor used on the server
    public MyRestService() {
        this.dataStoreService = DatastoreServiceFactory.getDatastoreService();
    }

    // constructor used by the unit tests
    public MyRestService(DataStoreService dataStoreService) {
        this.dataStoreService = dataStoreService;
    }

    public Response initialize(String DatabaseSchema) {
         ...
         // use this.dataStoreService instead of datastore
    }
}

现在,在您的测试方法中,您可以执行以下操作:

@Test
public void testInitializeWithGoodInput() {
    DataStoreService mockDataStoreService = mock(DataStoreService.class);
    MyRestService service = new MyRestService(mockDataStoreService);
    String goodInput = "...";
    Response response = service.initialize(goodInput);
    assertEquals(Response.Status.OK, response.getStatus());

    ArgumentCaptor<Entity> argument = ArgumentCaptor.forClass(Entity.class);
    verify(mock).put(argument.capture());
    assertEquals("the correct kind", argument.getValue().getKind());
    // ... other assertions
}
问题回答

你说的听起来更像集成测试和Mockito(或任何其他模拟框架)对你没有多大用处。

如果你想对你写的代码进行单元测试,Mockito当然是一个有用的工具。

我建议你阅读更多关于模拟/单元测试的内容,以及应该在哪些情况下使用它。

Mockito(通常)用于测试部分代码;例如,如果你正在使用REST服务,但不想进行全栈测试,你可以模拟连接到REST服务的服务,从而准确、一致地测试特定的行为。

为了在不访问数据库的情况下测试REST服务的内部部分(例如,特定的服务方法),您可以模拟DB子系统,只允许测试服务内部,而不涉及DB。此测试属于REST服务模块,而不是客户端。

要测试REST服务本身,您需要使用一个实际的客户端库,创建一个全栈集成测试。Mockito可以在这里用来模拟与REST服务消费无关的客户端部分。

最好的方法是使用wiremock添加以下依赖项com.github。tomakehurst wiremock 2.4.1 org.igniteraltime.smack smack-core 4.0.6

定义和使用wiremock,如下所示

@Rule
public WireMockRule wireMockRule = new WireMockRule(8089);

String response ="Hello world";
StubMapping responseValid = stubFor(get(urlEqualTo(url)).withHeader("Content-Type", equalTo("application/json"))
        .willReturn(aResponse().withStatus(200)
                .withHeader("Content-Type", "application/json").withBody(response)));

我同意这不是单元测试,而是集成测试,不管怎样,你宁愿看看球衣和嵌入式灰熊服务器测试。总之,这段代码在localhost:8888启动灰熊服务器(也可以启动数据库),然后设置客户端的jersey客户端并发送一个POST请求,该请求的响应应该被测试。这是一种集成,因为您正在测试服务器和数据库,您可以使用mockito来模拟数据库,但这取决于您的服务器和数据库的绑定程度。

(使用运动衫1.11和灰熊2.2进行测试)

    @BeforeClass
    public static void setUpClass() throws Exception {
        // starts grizzly
        Starter.start_grizzly(true);
        Thread.sleep(4000);
    }

    @Before
    public void setUp() throws Exception {
        client = new Client();
        webResource = client.resource("http://localhost:8888");
    }   

    @Test
    public void testPostSchemaDatabase() throws Exception {
        {
            String DatabaseSchema = "{ database_schema : {...}}";
            logger.info("REST client configured to send: "  + DatabaseSchema);
            ClientResponse response =  
                    webResource
                             .path("/initialize")
                             .type("application/json")
                             .post(ClientResponse.class, DatabaseSchema);
            //wait for the server to process
            Thread.sleep(2000);
            assertEquals(response.getStatus(), 204);    
            //test the response
        }       
    }

    @After
    public void after() throws JSONException
    {
            //probably you want to delete the schema at database and stop the server

}




相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...