我正在尝试用Mockito测试REST资源。下面是代码:
@Mock
private Service service;
@InjectMocks
private Resource resource;
....
doNothing().when(service).createItem(anyLong(), any(Item.class));
Response response = resource.createItem(item);
...
会引发以下异常:
[INFO] Running ...TestItems
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.447 s <<< FAILURE! - in ...TestItems
[ERROR] testCreateItem Time elapsed: 0.373 s <<< ERROR!
java.lang.IllegalArgumentException: RESTEASY003135: Class must be annotated with @Path to invoke path(Class)
at ...Tests.testCreateItem(TestItems.java:62)
REST资源看起来像这样:
@Path("/items")
public class Resource
{
....
@POST
public Response createItem (Item item)
{
...
}
}
我明白调用REST端点需要一个REST客户端,但在Mockito的单元测试中,这应该是可以工作的,因为我已经看到了几个这样做的例子。我哪里做错了?
提前感谢。
西摩
我在回答自己的问题。上面提到的异常是由REST端点引起的,它读起来像:
@POST
public Response createItem (Item item)
{
...
return Response.created(UriBuilder.fromResource(Item.class)
.path("/items/{id}").build(id)).build();
}
这里调用的UriBuilder.fromResource()方法当然是真正的方法。它测试是否用@Path注释了类。这会引发异常,因为它不是,因为它是一个mock。因此,像下面这样mock UriBuilder:
@Mock
private UriBuilder resteasyUriBuilder =
new ResteasyUriBuilder().path("/items");
...
when(resteasyUriBuilder.path("/items/{id}"))
.thenReturn(new ResteasyUriBuilder().path("/items/{id}"));
修复此问题。
因此,继续,我们的想法是修改被测试的类,以便注入UriBuilder,并在单元测试中注入模拟UriBuilder类。这意味着替换以下代码:
@POST
public Response createItem (Item item)
{
...
return Response.created(UriBuilder.fromResource(Item.class)
.path("/items/{id}").build(id)).build();
}
:
....
@Inject
private UriBuilder uriBuilder;
...
@POST
public Response createItem (Item item)
{
...
Response.created(uriBuilder.path("/items/{id}").build(id)).build();
}
然而,我不确定这句话:
when(resteasyUriBuilder.path("/items/{id}"))
.thenReturn(new ResteasyUriBuilder().path("/items/{id}"));
就是做恒等变换。无论如何…