Stub这种机制是用来模拟可能存在或还没写完的真实代码所产生的行为。它能使你顺利地测试系统的一部分,而无须考虑其它部分是否可行。通常,stub不会改变你测试的代码,只是加以适配以提供无缝整合。
Stub是代码的一部分,在运行时我们用stub替换真正的代码,忽略调用代码的实现。目的是用一个简单一点的行为替换一个复杂的行为,从而允许独立测试代码的某一部分。
我们为什么要用stub?
假设你同其他开发者一起开发一个项目,你想测试项目中你的那一部分,但其他部分还没完成,那该怎么办?解决的办法是用一个仿造品模拟缺失的那一部分。
为了使软件开发和测试同时进行,从而缩短软件的开发周期。通常会用stub代替成熟的外部系统,诸如,文件系统,到服务器的连接,数据库等。
4.1 用jetty作为嵌入式服务器代替Web服务器
JettySample.java:
import org.mortbay.http.HttpContext;
import org.mortbay.http.HttpServer;
import org.mortbay.http.SocketListener;
import org.mortbay.http.handler.ResourceHandler;
import org.mortbay.util.MultiException;
public class JettySample {
public static void main(String[] args) {
HttpServer server = new HttpServer();
SocketListener listener = new SocketListener();
listener.setPort(8080);
server.addListener(listener);
HttpContext context = new HttpContext();
context.setContextPath("/");
//设置资源文件的根目录
context.setResourceBase("./");
//添加资源处理器到httpContext,使之能提供文件系统中的文件
context.addHandler(new ResourceHandler());
server.addContext(context);
try {
//启动服务器
server.start();
} catch (MultiException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行main方法:
在IE地址栏输入http://localhost:8080/
4.2 Jetty替换web服务器的例子
1.服务器代码:
import java.io.IOException;
import java.io.OutputStream;
import junit.extensions.TestSetup;
import org.mortbay.http.HttpContext;
import org.mortbay.http.HttpException;
import org.mortbay.http.HttpFields;
import org.mortbay.http.HttpRequest;
import org.mortbay.http.HttpResponse;
import org.mortbay.http.HttpServer;
import org.mortbay.http.SocketListener;
import org.mortbay.http.handler.AbstractHttpHandler;
import org.mortbay.http.handler.ResourceHandler;
import org.mortbay.util.ByteArrayISO8859Writer;
import org.mortbay.util.MultiException;
public class WebClientServer extends TestSetup{
HttpServer server;
public WebClientServer(junit.framework.Test test) {
super(test);
}
//启动服务器
protected void setUp(){
server = new HttpServer();
SocketListener listener = new SocketListener();
listener.setPort(8080);
server.addListener(listener);
HttpContext context = new HttpContext();
context.setContextPath("/");
context.setResourceBase("./");
context.addHandler(new ResourceHandler());
//添加服务器返回信息
context.addHandler(new TestGetConnectHandler());
server.addContext(context);
try {
server.start();
} catch (MultiException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//关闭服务器
protected void tearDown(){
try {
server.stop();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//设置服务器返回信息
private class TestGetConnectHandler extends AbstractHttpHandler{
public void handle(String path, String params, HttpRequest request,HttpResponse response) throws HttpException, IOException {
OutputStream output = response.getOutputStream();
ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer();
writer.write("It works");
writer.flush();
response.setIntField(HttpFields.__ContentLength, writer.size());
writer.writeTo(output);
output.flush();
request.setHandled(true);
}
}
}
2.待测试类
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
public class WebClient {
public String getConnect(URL url){
StringBuffer content = new StringBuffer();
try {
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setDoInput(true);
InputStream input = connection.getInputStream();
byte[] buffer = new byte[2048];
int count;
while(-1 != (count = input.read(buffer))){
content.append(new String(buffer,0,count));
}
} catch (IOException e) {
return null;
}
return content.toString();
}
}
3.测试类
import java.net.MalformedURLException;
import java.net.URL;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
public class WebClientTest extends TestCase{
//启动服务器
public static Test suite(){
TestSuite suite = new TestSuite();
suite.addTestSuite(WebClientTest.class);
return new WebClientServer(suite);
}
//启动测试
public void testGetConnect() throws MalformedURLException {
WebClient webClient = new WebClient();
String result = webClient.getConnect(new URL("http://localhost:8080/testGetConnect"));
assertEquals("It works",result);
}
}
4.3替换连接
1.Http连接的处理类
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
public class StubHttpURLConnection extends HttpURLConnection {
private boolean isInput = true;
protected StubHttpURLConnection(URL url){
super(url);
}
@Override
public InputStream getInputStream() throws IOException {
if(!isInput){
throw new ProtocolException("Cann't read from URLConnection"
+ "if(doInput =false(call setDoInput(true)))");
}
ByteArrayInputStream bais = new ByteArrayInputStream(new String("It works").getBytes());
return bais;
}
@Override
public void disconnect() {}
@Override
public boolean usingProxy() {return false;}
@Override
public void connect() throws IOException {}
}
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import junit.framework.TestCase;
public class WebClientServerTwo extends TestCase{
//TestCase启动时加载
protected void setUp(){
//告诉url类用工厂来处理连接
URL.setURLStreamHandlerFactory(new StubStreamHandlerFactory());
}
private class StubStreamHandlerFactory implements URLStreamHandlerFactory{
//把所有链接连到http处理器
public URLStreamHandler createURLStreamHandler(String protocol) {
return new StubHttpURLStreamHandler();
}
}
private class StubHttpURLStreamHandler extends URLStreamHandler{
protected URLConnection openConnection(URL url) throws IOException {
//httpConnection处理器
return new StubHttpURLConnection(url);
}
}
public void testGetConnect() throws MalformedURLException {
WebClient webClient = new WebClient();
String result = webClient.getConnect(new URL("http://www.baidu.com"));
assertEquals("It works",result);
}
}