我应该如何对长功能进行单元测试?

时间:2013-07-17 19:02:47

标签: java unit-testing

如果我有一个很长的代码方法,它从2个或3个差异源收集数据并返回结果。我怎样才能重构它以使它更可单元测试?这个方法是一个web服务,我想从客户端代码调用一个来收集所有数据。

我可以将一些部分重构成更小的方法,这些方法更容易测试。但是目前的方法仍然会调用这5种方法,并且仍然不太可测试。假设Java是编程语言,是否有一种模式可以使这些代码可测试?

2 个答案:

答案 0 :(得分:4)

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

您需要做出的更改如下:

  • 对于每个数据源,创建一个接口来定义如何访问来自该源的数据,然后将用于返回数据的代码分解为实现此目的的单独类。
  • 依赖关系将数据源注入包含“long”函数的类中。
  • 对于单元测试,请注入每个数据源的模拟实现。

以下是一些代码示例,显示了它的外观 - 请注意,此代码仅仅是模式的说明,您需要一些更合理的名称。值得研究这种模式,并学习更多有关依赖注入的知识。嘲弄 - 单位测试员军械库中最强大的两种武器。

数据来源

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
        ...
    }
}

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

答案 1 :(得分:0)

“大”方法的测试看起来像集成测试,其中较小的方法可以被模拟。

如果你可以将“大”方法分成五个独立的方法,那么“大”方法可以进一步划分为隔离方法的语义/上下文有意义的组。

然后你可以为“大”方法模拟更大的孤立方法分组。