使用 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
。当我 运行 代码按预期工作时,我只是不知道如何测试它。
我想验证三件事:
- 我从 POST
收到 Todo
- 我获得了 OK (200) 状态。
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 对象。
我正在尝试对 resource class in Java's Dropwizard with the Spock testing framework 进行单元测试。
POSTing a Todo
到 /
应该将 Todo
添加到数据库并且 return
添加的 Todo
。当我 运行 代码按预期工作时,我只是不知道如何测试它。
我想验证三件事:
- 我从 POST 收到
- 我获得了 OK (200) 状态。
TodoStore.save
被调用一次。
Todo
下面的测试仅适用于第 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 对象。