我应该如何对长函数进行单元测试? [英] How should I unit-test a long function?

查看:32
本文介绍了我应该如何对长函数进行单元测试?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有一个很长的代码方法,它从 2 或 3 个不同的源收集数据并返回结果.如何重构它以使其更易于单元测试?此方法是一种网络服务,我想从客户端代码中进行一次调用以收集所有数据.

If i have a long method of code which gathers data from 2 or 3 difference sources and returns a result. How can I refactor it so that it is more unit-testable? This method is a webservice and I want to make one call from client code to gather all the data.

我可以将某些部分重构为更易于测试的更小的方法.但是当前的方法仍然会调用这 5 个方法,并且将保持较少的可测试性.假设 Java 作为编程语言,是否有使此类代码可测试的模式?

I can refactor some portions out into smaller methods which will be more testable. But the current method will still be calling those 5 methods and will remain less testable. Assuming Java as programming language, is there a pattern for making such code testable?

推荐答案

这是一个非常常见的测试问题,我遇到的最常见的解决方案是将数据源与使用数据的代码分开依赖注入.这不仅支持良好的测试,而且在使用外部数据源时通常也是一个很好的策略(良好的职责分离、隔离集成点、促进代码重用是这样做的一些原因).

This is a very common testing problem, and the most common solution I come across for this is to separate the sourcing of data from the code which uses the data using dependency injection. This not only supports good testing, but is generally a good strategy when working with external data sources (good segregation of responsibilities, isolates the integration point, promotes code reuse being some reasons for this).

您需要进行的更改类似于:

The changes you need to make go something like:

  • 对于每个数据源,创建一个接口来定义如何访问来自该源的数据,然后将返回数据的代码分解为实现此功能的单独类.
  • 依赖项将数据源注入包含long"函数的类.
  • 对于单元测试,注入每个数据源的模拟实现.

以下是一些代码示例,显示了这将是什么样子 - 请注意,此代码仅用于说明模式,您需要一些更合理的名称.值得研究这种模式并学习更多关于依赖注入的知识.嘲笑 - 单元测试员军械库中最强大的两种武器.

Here is some code examples showing what this would look like - note that this code is merely illustrative of the pattern, you will need some more sensible names for things. It would be worth studying this pattern and learning more about dependency injection & mocking - two of the most powerful weapons in the unit testers armory.

数据来源

public interface DataSourceOne {
    public Data getData();
}

public class DataSourceOneImpl implements DataSourceOne {
    public Data getData() {
        ...
        return data;
    }
}

public interface DataSourceTwo {
    public Data getData();
}

public class DataSourceTwoImpl implements DataSourceTwo {
    public Data getData() {
        ...
        return data;
    }
}

长方法类

public class ClassWithLongMethod {
    private DataSourceOne dataSourceOne;
    private DataSourceTwo dataSourceTwo;

    public ClassWithLongMethod(DataSourceOne dataSourceOne,
                               DataSourceTwo dataSourceTwo) {
        this.dataSourceOne = dataSourceOne;
        this.dataSourceTwo = dataSourceTwo;
    }

    public Result longMethod() {
        someData = dataSourceOne.getData();
        someMoreData = dataSourceTwo.getData();
        ...
        return result;
    }
}

单元测试

import org.junit.Test;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class ClassWithLongMethodTest {

    @Test
    public void testLongMethod() {

        // Create mocked data sources which return the data required by your test
        DataSourceOne dataSourceOne = mock(DataSourceOne.class);
        when(dataSourceOne.getData()).thenReturn(...);
        DataSourceTwo dataSourceTwo = mock(DataSourceTwo.class);
        when(dataSourceTwo.getData()).thenReturn(...);

        // Create the object under test using the mocked data sources
        ClassWithLongMethod sut = new ClassWithLongMethod(dataSourceOne,
                                                          dataSourceTwo);

        // Now you can unit test the long method in isolation from it's dependencies
        Result result = sut.longMethod();

        // Assertions on result
        ...
    }
}

请原谅(并纠正)任何语法错误,这些天我写的 Java 不多.

这篇关于我应该如何对长函数进行单元测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆