使用 Spock 测试库测试 POST 到 Dropwizard 资源

Use Spock testing library to test POST to Dropwizard resource

我正在尝试对 resource class in Java's Dropwizard with the Spock testing framework 进行单元测试。

POSTing a Todo/ 应该将 Todo 添加到数据库并且 return 添加的 Todo。当我 运行 代码按预期工作时,我只是不知道如何测试它。

我想验证三件事:

  1. 我从 POST
  2. 收到 Todo
  3. 我获得了 OK (200) 状态。
  4. TodoStore.save 被调用一次。

下面的测试仅适用于第 3 项。如何修复第 1 项和第 2 项?

相关提交的 Github 中提供了完整的工作代码。

TodoResourceTest.groovy

class TodoResourceTest extends Specification {

    TodoStore todoStore = Mock(TodoStore)

    @Rule
    ResourceTestRule resources = ResourceTestRule.builder()
            .addResource(new TodoResource(todoStore))
            .build()

    def "Adding a todo increases number of Todos"() {
        given: "no todos in TodoStore"
            Todo todo = new Todo(1, "title", null, null, null)
            todoStore.save(_ as Todo) >> todo

        when: "we add a Todo"
            def response = resources.client().target("/")
                .request(APPLICATION_JSON_TYPE)
                .post(entity(todo, APPLICATION_JSON_TYPE))
        then:
            // HELP: How do you test that the returned Todo is the same?

            // FAILS: Why doesn't this pass, it's returning 204 - no content
            response.getStatusInfo() == Response.Status.OK

            // PASSES
            1 * todoStore.save(_ as Todo)
    }
}

TodoResource.java

@Path("/")
@Produces(MediaType.APPLICATION_JSON)
public final class TodoResource {

    private final TodoStore todoStore;

    @Inject
    public TodoResource(TodoStore todoStore) {
        this.todoStore = todoStore;
    }

    @Timed
    @POST
    public Todo addTodo(Todo todo) {
        return todoStore.save(todo);
    }
}

TodoStore.java - 这是嘲笑的,所以没关系

public class TodoStore {

    private final DSLContext db;

    @Inject
    public TodoStore(DSLContext db) {
        this.db = db;
    }

    public Todo save(Todo todo) {
        final TodoRecord todoRecord = db.newRecord(TODO, todo);

        // id is determined by database, not user
        todoRecord.changed(TODO.ID, false);

        // url is determined based on id
        todoRecord.setUrl(null);

        if (todoRecord.getCompleted() == null) {
            todoRecord.setCompleted(false);
        }

        todoRecord.store();

        return todoRecord.into(Todo.class);
    }
}

我应该仔细检查文档。

来自 Combining Mocking and Stubbing 上的 Spock 文档。

When mocking and stubbing the same method call, they have to happen in the same interaction. In particular, the following Mockito-style splitting of stubbing and mocking into two separate statements will not work:

我的具体示例的解决方案是在 then 块中存根 todoStore.save,如下所示:

def "Adding a todo increases number of Todos"() {
    given: "no todos in TodoStore"
    Todo todo = new Todo(1, "title", null, null, null)

    when: "we add a Todo"
    def response = resources.client().target("/")
            .request(APPLICATION_JSON_TYPE)
            .post(entity(todo, APPLICATION_JSON_TYPE))


    then:
    // How do you test that the returned Todo is the same?

    response.getStatusInfo() == Response.Status.OK

    1 * todoStore.save(_ as Todo) >> todo
}

仍然不确定如何验证问题 #1,即响应 returns 相同的 Todo 对象。