我正在编写一个Java多线程网络应用程序,并且真正有困难想出一种方法来单元测试发送和接收来自网络客户端的通信的对象。单元测试Java多线程网络应用程序
该对象向多个客户端发送消息,然后等待来自客户端的响应。
随着每个客户端的响应,更新了仪表板式GUI。
更详细...
发送消息对象表示要被发送的文本消息,并且包含客户端的一个阵列,其应接收该消息。
消息对象负责将自己分配给所有适当的客户端。
当在Message对象上调用dispatch()方法时,该对象会为客户端阵列中的每个客户端生成一个新线程(MessageDispatcher)。
每个MessageDispatcher:
打开一个新的TCP套接字(Socket)连接到客户端
将消息传递给它的客户... PrintWriter的通过out.println(MSG文本)
创建一个'Status'对象,该对象被传递给Message对象中的Queue,然后传递给GUI。
每个状态对象表示以下事件之一:
消息传递到插座(通过为PrintWriter通过out.println())从客户机接收到
显示收据(经由的BufferedReader/InputStreamReader in.readline()... 阻塞,直到收到网络输入为止)
用户确认从客户端收到的收据(通过与上面相同的方法)
所以..我想单元测试Message对象。 (使用JUnit)
单元测试称为MessageTest.java(下面包含)。
我的第一步是用单个收件人设置一个Message对象。
然后我使用JMockit来创建一个模拟Socket对象,它可以向PrintWriter提供一个模拟OutputStream对象(我正在使用扩展OutputStream的ByteArrayOutputStream)。
然后,当MessageDispatcher调用(PrintWriter对象).out时,消息文本将理想地传递给我的模拟Socket对象(通过模拟OutputStream),它可以检查消息文本是否正确。
而对于使用InputStreamReader样品原理....的模拟Socket对象还提供供给一个模拟的BufferedReader其由MessageDispatcher称为(如前面提到的,在in.readLine MessageDispatcher块())一个模拟InputStreamReader的对象。此时模拟的BufferedReader应该提供一个假的确认到MessageDispatcher ...
// mock Socket
Mockit.redefineMethods(Socket.class, new Object()
{
ByteArrayOutputStream output = new ByteArrayOutputStream();
ByteArrayInputStream input = new ByteArrayInputStream();
public OutputStream getOutputStream()
{
return output;
}
public InputStream getInputStream()
{
return input;
}
});
如果这不是多线程的,这应该一切工作正常。不过,我不知道如何用多线程来做到这一点。任何人都可以给我任何建议或提示?
此外,如果您对设计有任何意见(例如,Message对象负责自己的交付,而不是单独的交付对象..“依赖注入”风格/单独的线程为每个客户交付),那么我会感兴趣也听到了。
UPDATE:这里是代码:
Message.java
public class Message {
Client[] to;
String contents;
String status;
StatusListener listener;
BlockingQueue<Status> statusQ;
public Message(Client[] to, String contents, StatusListener listener)
{
this.to = to;
this.contents = contents;
this.listener = listener;
}
public void dispatch()
{
try {
// open a new thread for each client
// keep a linked list of socket references so that all threads can be closed
List<Socket> sockets = Collections.synchronizedList(new ArrayList<Socket>());
// initialise the statusQ for threads to report message status
statusQ = new ArrayBlockingQueue<Status>(to.length*3); // max 3 status objects per thread
// dispatch to each client individually and wait for confirmation
for (int i=0; i < to.length; i++) {
System.out.println("Started new thread");
(new Thread(new MessageDispatcher(to[i], contents, sockets, statusQ))).start();
}
// now, monitor queue and empty the queue as it fills up.. (consumer)
while (true) {
listener.updateStatus(statusQ.take());
}
}
catch (Exception e) { e.printStackTrace(); }
}
// one MessageDispatcher per client
private class MessageDispatcher implements Runnable
{
private Client client;
private String contents;
private List<Socket> sockets;
private BlockingQueue<Status> statusQ;
public MessageDispatcher(Client client, String contents, List<Socket> sockets, BlockingQueue<Status> statusQ) {
this.contents = contents;
this.client = client;
this.sockets = sockets;
this.statusQ = statusQ;
}
public void run() {
try {
// open socket to client
Socket sk = new Socket(client.getAddress(), CLIENTPORT);
// add reference to socket to list
synchronized(sockets) {
sockets.add(sk);
}
PrintWriter out = new PrintWriter(sk.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(sk.getInputStream()));
// send message
out.println(contents);
// confirm dispatch
statusQ.add(new Status(client, "DISPATCHED"));
// wait for display receipt
in.readLine();
statusQ.add(new Status(client, "DISPLAYED"));
// wait for read receipt
in.readLine();
statusQ.add(new Status(client, "READ"));
}
catch (Exception e) { e.printStackTrace(); }
}
}
}
....和相应的单元测试:
MessageTest.java
public class MessageTest extends TestCase {
Message msg;
static final String testContents = "hello there";
public void setUp() {
// mock Socket
Mockit.redefineMethods(Socket.class, new Object()
{
ByteArrayOutputStream output = new ByteArrayOutputStream();
ByteArrayInputStream input = new ByteArrayInputStream();
public OutputStream getOutputStream()
{
return output;
}
public InputStream getInputStream()
{
return input;
}
});
// NB
// some code removed here for simplicity
// which uses JMockit to overrides the Client object and give it a fake hostname and address
Client[] testClient = { new Client() };
msg = new Message(testClient, testContents, this);
}
public void tearDown() {
}
public void testDispatch() {
// dispatch to client
msg.dispatch();
}
}
你可以发布一些你正在使用的代码,并告诉我们为什么代码不工作吗? – tster 2009-09-27 16:40:14
只是把2个主要对象 – Imme22009 2009-09-27 16:49:29