測試場景
在最近的測試中,涉及到了異步方法的單元測試。百度了一下之后铛只,基本上的案例都來自于這里:
https://fernandocejas.com/2014/04/08/unit-testing-asynchronous-methods-with-mockito/
對比之后,發(fā)覺和我們的場景略微有些差異。我們的場景是:
某個client是一個通信客戶端捷绑, 而在client內(nèi)部維護了一個Connector類的實例來真正地完成Socket層面的send/recv等消息的發(fā)送和接收的工作。另外氢妈,有一個IListener接口來處理收到的消息粹污,當(dāng)Connector收到消息時,將調(diào)用IListener的onMessage方法來處理消息首量。 這樣就完成了消息的異步處理壮吩。
被測的方法 client.login()的處理邏輯是:
1)通過connector.login來發(fā)送消息。
2)監(jiān)控client.getConnected()的狀態(tài)加缘,檢查是否登陸成功鸭叙。
當(dāng)?shù)讓樱ㄍㄐ艑樱┦盏较r,會通過connector.onMessage(data)來進行處理拣宏,即通知IListener沈贝,進而將登陸狀態(tài)設(shè)置為登陸成功。
因此勋乾,在測試過程中宋下,我們只需要Mock Connector嗡善,并在connector.login被調(diào)用時,通過answer 來調(diào)用
connector.onMessage(data)学歧,模擬來自對端的消息罩引。
測試代碼
具體的代碼如下:
1 測試用例
import org.junit.Assert;import org.junit.Before;import org.junit.Test;import org.mockito.ArgumentCaptor;import org.mockito.Captor;import org.mockito.MockitoAnnotations;import org.mockito.Spy;import static org.mockito.Mockito.*;import org.mockito.invocation.InvocationOnMock;import org.mockito.stubbing.Answer;import demo.org.powermock.async.Client;import demo.org.powermock.async.Connector;import demo.org.powermock.async.IListener;
public class TestClient {
String data="SUCCESS";
@Spyprivate Connector connector;
@Before public void initMocks() {
MockitoAnnotations.initMocks(this); }
@Testpublic void TestClientLogin() {
Client client=new Client(connector,"localhost");
Answeranswer = new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
connector.onMessage(data);
return null;
}
};
doAnswer(answer).when(connector).login("localhost");
client.login();
Assert.assertTrue(client.getConnected());
}
}
2 被mock的底層通信類
public class Connector {
private IListener listener;
public void onMessage(String data) {
listener.onMessage(data);
}
public void setListener(IListener listener) {
this.listener=listener;
}
public void login(String url) {
System.out.println("sending login request to "+url);
}
}
3 回調(diào)具體類
public class Listener implements IListener {
private Client client;
public Listener(Client client) {
this.client=client;
}
@Override
public void onMessage(String data) {
System.out.println(data);
if(data.contains("SUCCESS")) {
client.setConnected(true);
}
};
}
4 回調(diào)接口
public interface IListener {
public void onMessage(String data);
}
5 被測類
public class Client {
private Connector connector;
private String server;
boolean connected=false;
public Client(Connector connector,String server) {
this.connector=connector;
this.server=server;
this.connector.setListener(new Listener(this));
}
public void setConnected(boolean connected) {
this.connected=connected;
}
public boolean getConnected() {
return connected;
}
public void login() {
int times=0;
// sending login request to remote
connector.login(server);
// waiting for response from network
while(!getConnected() && times <10) {
try {
Thread.sleep(100);
times++;
} catch (InterruptedException e) {
e.printStackTrace();
}}}}