工厂方法重构策略
来源:互联网 发布:rss源码 编辑:程序博客网 时间:2024/06/06 03:56
先看下面的代码(模拟Web客户端读取远程URL上的资源):
public class WebClient
{
public String getContent( URL url )
{
StringBuffer content = new StringBuffer(); //用于存储从远程URL读取的资源
try
{
HttpURLConnection connection = (HttpURLConnection) url.openConnection(); //根据URL打开相应的连接
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();
}
}
如果我们想测试getContent()方法,我们首先想到可以mock一个URL,但是URL是一个final类,该方法行不通,然后我们想到可以mock一个HttpURLConnection,我们就应该让url的openConnection方法返回一个MockURLConnection,但是url是JDK的final类,我们无法控制它的内部方法,这是就应该想到重构WebClient类了。
下面是重构后的方法:
public class WebClient1
{
public String getContent( URL url )
{
StringBuffer content = new StringBuffer();
try
{
HttpURLConnection connection = createHttpURLConnection( url );
InputStream is = connection.getInputStream();
int count;
while ( -1 != ( count = is.read() ) )
{
content.append( new String( Character.toChars( count ) ) );
}
}
catch ( IOException e )
{
return null;
}
return content.toString();
}
protected HttpURLConnection createHttpURLConnection( URL url )
throws IOException
{
return (HttpURLConnection) url.openConnection();
}
}
这相较以前的实现有什么好处呢?他们的处理逻辑没有改变,只是添加了一个方法。想想我们如何才能在HttpURLConnection connection = createHttpURLConnection( url )处使方法返回一个mock HttpURLConnection?只能是覆写该方法,因此可以写一个测试辅助类,继承现在的WebClient类,看下面的实现(该类应该放在测试类的内部):
private class TestableWebClient extends WebClient {
private HttpURLConnection connection;
public void setHttpURLConnection(HttpURLConnection connection) {
this.connection = connection;
}
public HttpURLConnection createConnection(URL url) {
return this.connection;
}
}
这时,我们就可以让HttpURLConnection connection = createHttpURLConnection( url )处的方法返回一个mock HttpURLConnection了。实现也很简单:
public class TestWebClient {
@Test
public void testGetContentOk() throws Exception {
MockHttpURLConnection mockConnection = new MockHttpURLConnection();
mockConnection.setExpectedInputStream(
new ByteArrayInputStream("It works".getBytes()));
TestableWebClient client = new TestableWebClient();
client.setHttpURLConnection(mockConnection);
String result = client.getContent(new URL("http://localhost"));
assertEquals("It works", result);
}
}
上面的MockHttpURLConnection实现就不用说了,懂测试的人看上面的调用过程就可以写出来了。
综上可知:当我们要mock方法中的某些类的时候,而这种类型的变量的值又被设定并且与环境相关。如:HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 我们在测试时就得提供一个可靠的URL,但是我们并不想关心URL,如何做到呢,只需将等式右边的表达式改写成方法,然后用另一个辅助测试类来继承这个类并将这个方法覆写,以返回我们想要的对象。这样我们就不用关心URL了,做到了被测试的代码与环境相分离。可能有人会说我们这样测试的是测试辅助类,这不用担心,其实他们的业务逻辑是一样的。
所以说,测试对开发好的程序是很重要的!
- 工厂方法重构策略
- 代码重构之Spring+工厂+策略模式
- 简单工厂,工厂方法,抽象工厂,策略模式
- 使用工厂模式和策略模式重构复杂业务逻辑
- 机房重构利用策略模式+简单工厂实现消费金额的计算
- 【机房重构】——策略模式+简单工厂计算消费
- 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别
- 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别
- 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别
- 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别
- 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别
- 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别
- 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别
- 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别
- 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别
- 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别
- 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别
- 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别
- Address already in use: JVM_Bind(8005端口冲突)
- 程序开发的好习惯
- 第一次只出现一次的字符
- C++学习笔记24 函数模板
- PB9和PB11.5字符处理实例
- 工厂方法重构策略
- android View使用shape作为背景不能指定单边圆角的xml
- ros.usb_cam驱动的安装
- poj 1036 Gangsters(DP)
- linux安装图形界面
- Source insight 介绍
- 生成多个AWR报告
- 关于使用while(!filePCloud.eof())判断文件结尾进行数据输入装换时注意事项
- Linux编程基础:C标准库IO缓冲区与内核缓冲区的区别