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

时间:2016-02-11 02:02:37

标签: java testing groovy spock dropwizard

我尝试使用resource class对Java Dropwizard中的Spock testing framework进行单元测试。

Todo发布到/应将Todo添加到数据库并返回 添加的Todo。当我运行代码时,代码按预期工作,我只是无法弄清楚如何测试它。

我想验证三件事:

  1. 我从POST
  2. 返回Todo
  3. 我获得了OK(200)状态。
  4. TodoStore.save被调用一次。
  5. 以下测试仅适用于第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);
        }
    }
    

1 个答案:

答案 0 :(得分:0)

我应该仔细检查文档。

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

  

当模拟和存根相同的方法调用时,它们必须在相同的交互中发生。特别是,以下Mockito风格将存根和模拟拆分为两个单独的语句将工作:

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

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,响应返回相同的Todo对象。