java - 我应该如何对长函数进行单元测试?

标签 java unit-testing

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

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

最佳答案

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

您需要进行的更改如下:

  • 对于每个数据源,创建一个接口(interface)来定义如何访问来自该源的数据,然后将返回数据的代码分解为一个单独的类来实现它。
  • 依赖项将数据源注入(inject)到包含“长”函数的类中。
  • 对于单元测试,注入(inject)每个数据源的模拟实现。

这里有一些代码示例展示了它的样子——请注意,这段代码只是模式的说明,您将需要一些更合理的名称。值得研究这种模式并了解更多有关依赖注入(inject)和模拟的信息 - 单元测试人员军械库中最强大的两种武器。

数据源

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 不多。

关于java - 我应该如何对长函数进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17708127/

相关文章:

c# - TestContext.TestName 属性永远不会改变

c# - 为什么我应该偏爱 stub 而不是模拟?

java - GridBagLayout 被标记为错误

java - 如何在 onAction 方法中从 TextField 获取文本?

java - Fragments vs AsyncTask vs IntentService vs 长时间运行的操作

java - 无法在 Spring 3.2.8 和 junit 4.4 中 Autowiring 现场执行 Junit 测试

flutter - 如何比较 flutter 单元测试的期望函数中的两个列表?

c++ - 如何从头开始在 VS 2019 中设置 Google Test?

java - Java 中的模式和匹配器正则表达式

Java,如何将 GMT 时间更改为本地时间?