如何设计单元测试类

Seb*_*ian 2 java unit-testing

我有一个如下所示的 Java 类:

public class MyClass {

    /** Database Connection. */
    private dbCon;

    public MyClass() {
        dbCon = ...
    }

    public void doSomethingWith(MyData data) {
        data = convertData(data);
        dbCon.storeData(data);
    }

    private MyData convertData(MyData data) {
        // Some complex logic...
        return data;
    }
}
Run Code Online (Sandbox Code Playgroud)

由于这个类的真正逻辑在于convertData()方法,所以我想为这个方法编写一个单元测试。所以我读了这篇文章

如何测试私有函数或具有私有方法、字段或内部类的类?

很多人说需要测试私有方法是一种设计味道。怎样才能做得更好呢?

我看到两种方法:

  1. convertData()使用公共 api 将方法提取到某个实用程序类中。但我认为这也是一种不好的做法,因为此类实用程序类将违反单一责任原则,除非我创建大量可能只有一两个方法的实用程序类。

  2. 编写第二个允许注入的构造函数dbCon,这允许我注入数据库连接的模拟版本并针对公共doSomething()方法运行测试。这将是我首选的方法,但也有关于模拟的需要如何也是一种代码味道的讨论。

对于这个问题有什么最佳实践吗?

Nko*_*osi 6

将 ConvertData() 方法提取到某个具有公共 api 的实用程序类中。但我认为这也是一种不好的做法,因为这样的实用程序类将违反单一职责原则,除非我创建大量可能只有一两个方法的实用程序类。

你对此的解释是错误的。这正是 SRP 和 SoC (关注点分离)所建议的

public interface MyDataConverter {
    MyData convertData(MyData data);
}

public class MyDataConverterImplementation implements MyDataConverter {
    public MyData convertData(MyData data) {
        // Some complex logic...
        return data;
    }
}
Run Code Online (Sandbox Code Playgroud)

convertData现在可以单独测试实现MyClass

编写第二个构造函数,允许注入 dbCon,这允许我注入数据库连接的模拟版本并针对公共 doSomething() 方法运行测试。这将是我首选的方法,但也有关于模拟的需要如何也是一种代码味道的讨论。

又错了。研究显式依赖原则。

public class MyClass {
    private DbConnection dbCon;
    private MyDataConverter converter;

    public MyClass(DbConnection dbCon, MyDataConverter converter) {
        this.dbCon = dbCon;
        this.converter = converter;
    }

    public void doSomethingWith(MyData data) {
        data = converter.convertData(data);
        dbCon.storeData(data);
    }
}
Run Code Online (Sandbox Code Playgroud)

MyClass现在更加诚实地了解执行其所需功能所需的内容。

它还可以通过注入模拟依赖项来单独进行单元测试。