JUnit学习笔记9---mock object进行孤立测试3
2013-04-18 10:39
543 查看
实践HTTP连接示例程序
为了了解mock objects在实际的例子中是如何工作的,书中举了这样的一个例子,它打开了一个远程的Http连接,读取页面的内容,在上面的笔记中使用了stub技术进行了测试,当时也分析了stub的不可取之处,那么今天介绍的mock技术可以弥补!那就再进行一测试吧,假期八天的时间,再我看来就是无情的测试。。。
我们将要学习使用java接口类HttpURLConnection编写mock。书中展示了如何从初始的测试开始,如何进一步的改善,以及如何的修改源代码使之更加的灵活。还有如何使用mock测试错误的情况。 (看不到图的朋友点击这里!)
定义mock object
下图说明了mock object的定义,MockURL类替换了真正的URL类,在getContent中所有对URL类的调用由MockURL类接管。就像你看到的那样,测试一个controller:它创建并配置了测试中mock必须具备的功能,用MockURL类代替了真正的URL类,运行测试。
上面的示例图展示了mock objects策略有趣的一面:在代码中能够换入mock。有心的您会注意到,因为URL类是final类型的,它根本就不能创建出一个扩展的MockURL类。在接下来的节里,我们将展示这个技巧如何是以不同的方式执行的。在任何的案例中,当用到mock objects策略时,把真正的mock换做mock是一个难点。这也许可以看作mock objects的一个缺点,因为通常要修改你的代码,以提供暗门。
打开HTTP连接的代码
尝试1:简单的方法重构技法
我们的想法是能够不依赖于web服务器的真正的HTTP连接,独立的测试getContent方法。如果你应用在JUnit学习笔记7中的方法,那么就是遍一个mockURL,在其中,url.openConnection方法返回一个mock HttpURLConnection。MockHttpURLConnection类将提供一个测试决定getInputStream方法返回什么的实现。理论上,你能写入下的测试:
不幸的是,这个方法并没有用!JDK URL类是一个final类,没有任何的URL接口可以用!继承到此为止,你需要找到另外的一个解决方案!很可能是mock另外的一个对象。一个办法就是替换URLStreamHandlerFactory类,在笔记6中研究了这个方法,那么让我们找出一个使用mock objects的办法吧,那就是重构getContent方法。如果你思考一下就会发现,这个方法做了两件事情,它取了HttpURLConnection对象,然后从中读取内容。可以将其重构,结果就是下面的类。
上面的部分就是重构的结果,你现在调用createHttpURLConnection方法,创建Http连接。
该方法如何使得你测试getContent方法更有效呢?你可以用一个技巧:写一个继承WebClient类的测试辅助类,并且复写它的createHttpURLConnection方法,把它传递给mock HttpURLConnection对象。测试代码如下:
这是一个常用的重构技巧,叫做Method Factory重构。它在mock的类中没有接口时特别的有用。策略是扩展这个类,加入一些setter方法来控制,覆写一些getter方法来得到测试要的东西。对这个例子而言,这个方法不错,但是也不完美。有点像海森堡的测不准原理:被测的子类改变了它的行为。
在下个笔记中,将记录另外的一种尝试:使用类工厂进行重构!
为了了解mock objects在实际的例子中是如何工作的,书中举了这样的一个例子,它打开了一个远程的Http连接,读取页面的内容,在上面的笔记中使用了stub技术进行了测试,当时也分析了stub的不可取之处,那么今天介绍的mock技术可以弥补!那就再进行一测试吧,假期八天的时间,再我看来就是无情的测试。。。
我们将要学习使用java接口类HttpURLConnection编写mock。书中展示了如何从初始的测试开始,如何进一步的改善,以及如何的修改源代码使之更加的灵活。还有如何使用mock测试错误的情况。 (看不到图的朋友点击这里!)
定义mock object
下图说明了mock object的定义,MockURL类替换了真正的URL类,在getContent中所有对URL类的调用由MockURL类接管。就像你看到的那样,测试一个controller:它创建并配置了测试中mock必须具备的功能,用MockURL类代替了真正的URL类,运行测试。
上面的示例图展示了mock objects策略有趣的一面:在代码中能够换入mock。有心的您会注意到,因为URL类是final类型的,它根本就不能创建出一个扩展的MockURL类。在接下来的节里,我们将展示这个技巧如何是以不同的方式执行的。在任何的案例中,当用到mock objects策略时,把真正的mock换做mock是一个难点。这也许可以看作mock objects的一个缺点,因为通常要修改你的代码,以提供暗门。
打开HTTP连接的代码
package junitbook.fine.try1; import java.net.URL; import java.net.HttpURLConnection; import java.io.InputStream; import java.io.IOException; 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(); } }
尝试1:简单的方法重构技法
我们的想法是能够不依赖于web服务器的真正的HTTP连接,独立的测试getContent方法。如果你应用在JUnit学习笔记7中的方法,那么就是遍一个mockURL,在其中,url.openConnection方法返回一个mock HttpURLConnection。MockHttpURLConnection类将提供一个测试决定getInputStream方法返回什么的实现。理论上,你能写入下的测试:
public void testGetContentOk() throws Exception { MockHttpURLConnection mockConnection = new MockHttpURLConnection(); ;创建一个mock HttpURLConnection.建立它是为了在其上调用 mockConnection.setExpectedInputStream( ;getInputStream方法时返回包含“It works”的字符流 new ByteArrayInputStream("It works".getBytes())); ; MockURL mockURL=new MockURL(); ;创建一个mock URL也是同一个道理,当url.openConnection mockURL.setupOpenConnection(mockConnection); ;被调用时,返回MockURLConnection. WebClient client=new WebClient(); String result = client.getContent( ;调用getContent方法来测试,把你的MockURL实例传给它 mockURL); assertEquals("It works", result); ;确认结果 }
不幸的是,这个方法并没有用!JDK URL类是一个final类,没有任何的URL接口可以用!继承到此为止,你需要找到另外的一个解决方案!很可能是mock另外的一个对象。一个办法就是替换URLStreamHandlerFactory类,在笔记6中研究了这个方法,那么让我们找出一个使用mock objects的办法吧,那就是重构getContent方法。如果你思考一下就会发现,这个方法做了两件事情,它取了HttpURLConnection对象,然后从中读取内容。可以将其重构,结果就是下面的类。
package junitbook.fine.try1; import java.net.URL; import java.net.HttpURLConnection; import java.io.InputStream; import java.io.IOException; public class WebClient { public String getContent(URL url) { StringBuffer content = new StringBuffer(); try { HttpURLConnection connection = createHttpURLConnection(url); 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(); } protected HttpURLConnection createHttpURLConnection(URL url) throws IOException { return (HttpURLConnection) url.openConnection(); } }
上面的部分就是重构的结果,你现在调用createHttpURLConnection方法,创建Http连接。
该方法如何使得你测试getContent方法更有效呢?你可以用一个技巧:写一个继承WebClient类的测试辅助类,并且复写它的createHttpURLConnection方法,把它传递给mock HttpURLConnection对象。测试代码如下:
package junitbook.fine.try1; import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import junit.framework.TestCase; public class TestWebClientMock extends TestCase { 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( ;getContent方法接收URL作为参数,所以你要传一个参数 new URL("http://localhost")); assertEquals("It works", result); } private class TestableWebClient extends WebClient ;配置TestableWebClient,以便createHttpURLConnection方法返回一个mock { ; object private HttpURLConnection connection; public void setHttpURLConnection( HttpURLConnection connection) { this.connection = connection; } public HttpURLConnection createHttpURLConnection(URL url) throws IOException { return this.connection; } } }
这是一个常用的重构技巧,叫做Method Factory重构。它在mock的类中没有接口时特别的有用。策略是扩展这个类,加入一些setter方法来控制,覆写一些getter方法来得到测试要的东西。对这个例子而言,这个方法不错,但是也不完美。有点像海森堡的测不准原理:被测的子类改变了它的行为。
在下个笔记中,将记录另外的一种尝试:使用类工厂进行重构!
相关文章推荐
- JUnit学习笔记10---mock object进行孤立测试4
- JUnit学习笔记10---mock object进行孤立测试4
- JUnit学习笔记7---mock objects进行孤立测试1
- JUnit学习笔记8---mock object进行独立测试2
- JUnit学习笔记7---mock objects进行孤立测试1
- JUnit学习笔记8---mock object进行独立测试2
- JUnit学习笔记6---用stub进行粗粒度测试
- JUnit学习笔记9---mock object进行孤立测试3
- JUnit学习笔记16---用JSP和taglib进行单元测试3
- JUnit学习笔记19---对数据库应用程序进行单元测试3
- JUnit学习笔记15---对JSP和taglib进行单元测试2
- JUnit学习笔记18---对数据库应用程序进行单元测试2
- JUnit学习笔记20---对数据库应用程序进行单元测试4
- JUnit学习笔记6---用stub进行粗粒度测试
- eclipse初步学习笔记(快捷键 运行调试 junit测试框架)
- junit---用mock object进行隔离测试(下)
- Junit学习笔记之三:测试驱动开发
- JUnit学习笔记3——chapter4.探索软件测试
- JUnit学习笔记13---对servlet和filter进行单元测试2
- junit测试工具学习笔记1