junit使用stub进行单元测试
stub是代码的一部分,我们要对某一方法做单元测试时,可能涉及到调用第三方web服务。假如当前该服务不存在或不可用咋办?好办,写一段stub代码替代它。
stub 技术就是把某一部分代码与环境隔离起来(比如,通过替换 Web服务器、文件系统、数据库等手段)从而进行单元测试的。
下面演示一个例子,利用jetty编写相关的stub充当web服务器,返回适当内容。
环境: idea + spring boot + jetty
关于jetty服务器,对比tomcat更轻量级,可轻松嵌入java代码启动它。
如何在项目中启动一个jetty服务器?
package com.lhy.junitkaifa.stubs;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ResourceHandler;
/**
* @author xusucheng
* @create 2018-12-20
**/
public class JettySample {
public static void main(String[] args) throws Exception {
Server server = new Server( 8081 );
ContextHandler context = new ContextHandler(server,"/");
//默认为项目根目录
context.setResourceBase(".");
context.setHandler(new ResourceHandler());
server.setStopAtShutdown( true );
server.start();
}
}
请求:http://localhost:8081
编写一个获取url内容的工具方法叫WebClient
package com.lhy.junitkaifa.stubs;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* 读取指定URL内容
* @author xusucheng
* @create 2018-12-20
**/
public class WebClient {
public String getContent( URL url )
{
StringBuffer content = new StringBuffer();
try
{
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput( true );
InputStream is = connection.getInputStream();
byte[] buffer = new byte[2048];
int count;
while ( -1 != ( count = is.read( buffer ) ) )
{
content.append( new String( buffer, 0, count ) );
}
}
catch ( IOException e )
{
return null;
}
return content.toString();
}
public static void main(String[] args) throws Exception{
WebClient wc = new WebClient();
String content = wc.getContent(new URL("http://www.baidu.com/"));
System.out.println(content);
}
}
编写测试类TestWebClient
package com.lhy.junitkaifa.stubs;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.ByteArrayISO8859Writer;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
* @author xusucheng
* @create 2018-12-20
**/
public class TestWebClient {
private WebClient client = new WebClient();
private static final int PORT=8081;
@BeforeClass
public static void setUp() throws Exception{
System.out.println("====================Befor Class=====================");
Server server = new Server(PORT);
TestWebClient t = new TestWebClient();
ContextHandler contentOkContext = new ContextHandler(server,"/testGetContentOk");
contentOkContext.setHandler(t.new TestGetContentOkHandler());
ContextHandler contentErrorContext = new ContextHandler(server,"/testGetContentError");
contentErrorContext.setHandler(t.new TestGetContentServerErrorHandler());
ContextHandler contentNotFoundContext = new ContextHandler(server,"/testGetContentNotFound");
contentNotFoundContext.setHandler(t.new TestGetContentNotFoundHandler());
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { contentOkContext, contentErrorContext, contentNotFoundContext});
server.setHandler(handlers);
server.setStopAtShutdown( true );
server.start();
}
@Test
public void testGetContentOk()
throws Exception
{
String result = client.getContent( new URL( "http://localhost:"+PORT+"/testGetContentOk" ) );
assertEquals( "It works", result );
}
@Test
public void testGetContentError()
throws Exception
{
String result = client.getContent( new URL( "http://localhost:"+PORT+"/testGetContentError/" ) );
assertNull( result );
}
@Test
public void testGetContentNotFound()
throws Exception
{
String result = client.getContent( new URL( "http://localhost:"+PORT+"/testGetContentNotFound" ) );
assertNull( result );
}
@AfterClass
public static void tearDown()
{
// Do nothing becuase the Jetty server is configured
// to stop at shutdown.
System.out.println("====================After Class=====================");
}
/**
* 正常请求处理器
*/
private class TestGetContentOkHandler
extends AbstractHandler
{
@Override
protected void doStart() throws Exception {
super.doStart();
}
@Override
public void setServer(Server server) {
super.setServer(server);
}
@Override
public void handle(String s, Request request, HttpServletRequest httpServletRequest, HttpServletResponse response) throws IOException, ServletException {
System.out.println("======================TestGetContentOkHandler=======================");
OutputStream out = response.getOutputStream();
ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer();
writer.write( "It works" );
writer.flush();
response.setIntHeader( HttpHeaders.CONTENT_LENGTH, writer.size() );
writer.writeTo( out );
out.flush();
request.setHandled(true);
}
}
/**
* 异常请求处理器
*/
private class TestGetContentServerErrorHandler
extends AbstractHandler
{
@Override
public void handle(String s, Request request, HttpServletRequest httpServletRequest, HttpServletResponse response) throws IOException, ServletException {
response.sendError( HttpServletResponse.SC_SERVICE_UNAVAILABLE );
}
}
/**
* 404处理器
*/
private class TestGetContentNotFoundHandler
extends AbstractHandler
{
@Override
public void handle(String s, Request request, HttpServletRequest httpServletRequest, HttpServletResponse response) throws IOException, ServletException {
response.sendError( HttpServletResponse.SC_NOT_FOUND );
}
}
}
直接运行该类,结果为:
标签:
junit stub
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构