JUnit学习笔记9---mock object进行孤立测试3

实践HTTP连接示例程序  

   为了了解mock objects在实际的例子中是如何工作的,书中举了这样的一个例子,它打开了一个远程的Http连接,读取页面的内容,在上面的笔记中使用了stub技术进行了测试,当时也分析了stub的不可取之处,那么今天介绍的mock技术可以弥补!那就再进行一测试吧,假期八天的时间,再我看来就是无情的测试。。。

    我们将要学习使用java接口类HttpURLConnection编写mock。书中展示了如何从初始的测试开始,如何进一步的改善,以及如何的修改源代码使之更加的灵活。还有如何使用mock测试错误的情况。  (看不到图的朋友点击这里!)

    TM截图未命名

定义mock object

     下图说明了mock object的定义,MockURL类替换了真正的URL类,在getContent中所有对URL类的调用由MockURL类接管。就像你看到的那样,测试一个controller:它创建并配置了测试中mock必须具备的功能,用MockURL类代替了真正的URL类,运行测试。

TM截图未命名

上面的示例图展示了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方法来得到测试要的东西。对这个例子而言,这个方法不错,但是也不完美。有点像海森堡的测不准原理:被测的子类改变了它的行为。

   在下个笔记中,将记录另外的一种尝试:使用类工厂进行重构!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值