Java JUnit/Mockito验证`any(HttpPut.class)`但是当其他实例也被使用时会通过
我有一个服务类,它调用RESTAPI来获取、创建、更新和删除订阅者。Uri保持不变,但HTTP方法会如您所期望的那样更改。我想测试给出的正确方法。下面是updateSubscriber及其测试的示例Java JUnit/Mockito验证`any(HttpPut.class)`但是当其他实例也被使用时会通过,java,junit,mockito,Java,Junit,Mockito,我有一个服务类,它调用RESTAPI来获取、创建、更新和删除订阅者。Uri保持不变,但HTTP方法会如您所期望的那样更改。我想测试给出的正确方法。下面是updateSubscriber及其测试的示例 public class MyService { HttpClient httpClient; public MyService(HttpClient httpClient) { this.httpClient = httpClient; } /
public class MyService {
HttpClient httpClient;
public MyService(HttpClient httpClient) {
this.httpClient = httpClient;
}
//...
public int updateSubscriber(Subscriber subscriber) throws ... {
// PUT is the correct method for this request
HttpResponse response = httpClient.execute( new HttpPut( "https://example.org/api/subscribers" ) );
//...
}
//...
下面是我对JUnit和Mockito的测试:
@RunWith(MockitoJUnitRunner.class)
public class MyServiceTest
{
@Mock
private HttpClient mockHttpClient;
@Mock
private HttpResponse mockResponse;
@Mock
private StatusLine mockStatusline;
@Mock
private HttpEntity mockEntity;
// test subject
private MyService myService;
@Before
public void setup() {
// // this will just ensure http* objects are returning our mocked instances so we can manipulate them..
// when(mockHttpClient.execute(any(HttpGet.class))).thenReturn(mockResponse);
// when(mockHttpClient.execute(any(HttpPost.class))).thenReturn(mockResponse);
// when(mockHttpClient.execute(any(HttpPut.class))).thenReturn(mockResponse);
// when(mockHttpClient.execute(any(HttpDelete.class))).thenReturn(mockResponse);
// when(mockResponse.getStatusLine()).thenReturn(mockStatusline);
// when(mockStatusline.getStatusCode()).thenReturn(HttpStatus.SC_OK);
myService = new MyService(mockHttpClient);
}
@Test
public void testUpdateSubscriber() throws ...
{
when(mockHttpClient.execute(any(HttpPut.class))).thenReturn(mockResponse);
when(mockResponse.getStatusLine()).thenReturn(mockStatusline);
when(mockStatusline.getStatusCode()).thenReturn(HttpStatus.SC_OK);
String responseString = "...";
// this is consumed by a static method which we cannot mock, so we must deal with an actual entity instance
BasicHttpEntity entity = new BasicHttpEntity();
entity.setContent(new ByteArrayInputStream(responseString.getBytes()));
when(mockResponse.getEntity()).thenReturn(entity);
// create a test case Subscriber instance
Subscriber subscriber = new Subscriber();
int statusCode = myService.updateSubscriber(subscriber);
assertEquals(HttpStatus.SC_OK, statusCode);
// just confirm that an HTTP request was made
// TODO this isn't working, still passes when wrong Http* method used
verify(mockHttpClient, times(1)).execute(any(HttpPut.class));
}
//...
但是,当我(错误地)拥有另一个Http*方法实例时,它仍然传递:
// this is wrong, and should fail, but passed :(
HttpResponse response = httpClient.execute( new HttpGet( "https://example.org/api/subscribers" ) );
我真的希望能够测试这一点,因为如果方法错误,执行的操作可能是错误的。此测试旨在确保PUT方法正确用于updateSubscriber的HTTP请求。有什么想法吗?测试通过,因为
HtppPut
和HttpGet
都是HttpRequestBase
的实现类,将模拟从HttpRequestBase
类更改为HttpPut
类
when(mockHttpClient.execute(any(HttpPut.class))).thenReturn(mockResponse);
因此,现在如果您尝试使用
GET
调用测试将失败,因为GET
调用没有存根不确定这是否是我问题的正确答案,但我使用自定义参数匹配器成功地使测试按预期工作:
package uk.ac.strath.matchers;
import org.apache.http.client.methods.HttpUriRequest;
import org.mockito.ArgumentMatcher;
public class HttpMethodMatcher implements ArgumentMatcher<HttpUriRequest> {
private String expectedClassName;
// constructors
public HttpMethodMatcher(String expectedClassName) {
this.expectedClassName = expectedClassName;
}
@Override
public boolean matches(HttpUriRequest httpMessage) {
if (httpMessage.getClass().getName().equals(expectedClassName)) {
return true;
}
return false;
}
}
本教程很有帮助:我想如果我通过了
HttpRequestBase.class
in,并使用验证,会是这样吗?我只是告诉when
在使用HttpRequestBase的任何实现时返回相同的模拟实例。不管怎样,我已经按照你的建议进行了更改,并更新了上面的代码,但是,即使我正在验证另一个类实例是否已传递给execute
方法,也只传递相同的结果。我不知道为什么要在setup
方法中添加存根,以及为什么需要所有类型的存根@Martyn请查看一些spring junit示例在每次测试之前都不运行安装程序?我把它们放在这里是因为我不想在每个测试方法中重复相同的代码。我不认为在每个方法中都会调用相同的put
request@MartynOK,为了排除这种情况,我已经将这些行从设置中移到了测试方法中。我在运行测试时也遇到了同样的问题。我更新了我原来的帖子。你对mockito的看法是什么?在1.x中,任何(类)的行为都是不同的。您是否调用此httpClient.execute(新的HttpGet(“https://example.org/api/subscribers" ) );代码>直接在httpClient
或mockHttpClient
上?上面的代码显示您没有对mock进行GET
调用,并且还添加了一条语句来验证GET
调用verify(mockHttpClient,times(1)).execute(any(HttpGet.class))代码>在测试中,您将看到我作为依赖项传入mockHttpClient,因此这个实例接收HttpGet(在其他情况下是Http*whetever方法)。我使用的是Mockito版本1.9.5。
verify(mockHttpClient, times(1)).execute( argThat(new HttpMethodMatcher( HttpGet.class.getName() )) );