你如何对需要很长时间的方法进行单元测试?

时间:2011-05-12 18:09:21

标签: java eclipse unit-testing

我是单元测试的新手。有一种方法如下:

public Image getImage(String url) {
    Document pageSource = fecthSource(url);
    Image myImage = parseHtmlToImage(pageSource);
    return Image;
}

我写了一个单元测试:

@test
public void getRightPicture() {
    Image img = imageFetcher.getImage("http://www.123.com");
    assertEquals(img.sourceUrl, "http://www.123.com/456.png");
    Image img = imageFetcher.getImage("http://www.abc.com");
    assertEquals(img.sourceUrl, "http://www.abc.com/def.png");
}

但是如果访问Internet需要很长时间。我通常想使用本地HTML文件来测试此方法,但有时会测试Web版本。

有什么建议吗?

4 个答案:

答案 0 :(得分:3)

您的单元测试无需验证互联网是否正常工作。您应该提供一些模拟HTML文件并指向测试的那些文件。由于您正在处理网址,因此您应该能够指定"file:///path/to/test.html"之类的路径来代替网址。

答案 1 :(得分:3)

简答:依赖倒置。

更长的答案:

问题可能与fetchSource正在做的事情有关;没有看到细节,这个答案将不得不有点模糊。我假设fetchSource调用实际执行检索的东西,并且这样做的细节并不是你真正感兴趣的测试。我还假设你打算在写“fecht”的任何地方写“fetch”,但这对答案来说并不是特别重要。

你想抽象掉fetchSource的具体内容,这样你就可以专注于测试对你来说重要的东西(parseHtmlToImage?)。有很多方法可以做到这一点:

  • 使用接口的存根实现构造imageFetcher,通过该接口实际检索URL,通过构造函数传递它(反转依赖关系);你的存根扮演“互联网”的角色并返回一个预设的响应。
  • 如果您无法创建接口的存根实现,请引入一个适配器接口,其中您有一个生产实现,该实现使用您用于检索的当前接口,以及您用于测试的存根实现。 / LI>

这是编写可测试代码的一种非常标准的技术(查找依赖性倒置原则)。

答案 2 :(得分:1)

这里有两个选项 -

  1. 本地文件肯定是一种更快捷的做事方式;另外,你可以做的是创建一个模拟对象(参见Mockito或Easymock以便于模拟),这样它就可以模拟你要测试的类中的fetchURL方法;

  2. 在其他时候,当你想从网上获取URL时 - 由于你正在移开外部的测试依赖项,它在那时变得不仅仅是单元测试了。在这种情况下,您必须处理副作用,即网络延迟,资源可用性等。此集成测试的一个优化是,如果多个测试依赖于它,则缓存资源。这样你每次都不需要通过网络获取。

答案 3 :(得分:1)

要扩展上面的依赖注入答案:

所以你有:

class ImageFetcher {
    public Image getImage(String url) {
       Document pageSource = fetchSource(url);
       Image myImage = parseHtmlToImage(pageSource);
       return Image;
    }
    private Document fetchSource(String url) {
        // ... Network IO etc
    }
    private Image parseHtmlToImage(Document pageSource) {
        // Parsing logic
        // Network IO
        return image;
    }
}

第一个问题是“这是否真的属于”ImageFetcher“.IMO fetchSource没有。那(对我来说)听起来像是一个不同的”Web Utils“类会做的事情。我也会提到一个从ImageFetcher到utils类的图像。

class ImageFetcher {
    private WebUtils webUtils; 
    public ImageFetcher(webUtils webUtils) {
      this.webUtils = webUtils;
    }


    public Image getImage(String url) {
       Document pageSource = webUtils.fetchSource(url);
       Image myImage = parseHtmlToImage(pageSource);
       return Image;
    }

    private Image parseHtmlToImage(Document pageSource) {
        imageURL = // Parsing logic
        image = webUtils.fetchImage(imageURL);
        return image;
    }
}

现在Image Fetcher主要关心的是确定要使用哪个图像。它不再需要关心如何从网络获取该图像。可以模拟WebUtils进行单元测试。

@test
public void getImage_ReturnsBannerImage() {
     Image expected = // ...


     String html = "<html><img src="fred"/>...</html>"; // Keep this short and simple.
     mockedWebUtil.fetchSource(Any.String).returns(html);
     mockedWebUtil.fetchImage("fred").returns(expected);

     var subject = new ImageFetcher(mockedWebUtil);
     var actual = subject.getImage("blah");

     Assert.AreEqual(expected, actual);
}