Java 如何为单元测试设计类

Java 如何为单元测试设计类,java,unit-testing,Java,Unit Testing,我有一个Java类,如下所示: public class MyClass { /** Database Connection. */ private dbCon; public MyClass() { dbCon = ... } public void doSomethingWith(MyData data) { data = convertData(data); dbCon.storeData(dat

我有一个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;
    }
}
因为这个类的真正逻辑在于
convertData()
方法,所以我想为这个方法编写一个单元测试。 所以我读了这篇文章

很多人说测试私有方法的需要是一种设计的味道。如何才能做得更好

我看到两种方法:

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

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

  • 关于这个问题有什么最佳实践吗

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

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

    convertData
    实现现在可以独立于
    MyClass

    编写第二个构造函数,允许注入dbCon,这允许我注入数据库连接的模拟版本,并针对public 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);
        }
    }
    
    MyClass
    现在更诚实地说明了执行所需功能所需的内容

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

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

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

    convertData
    实现现在可以独立于
    MyClass

    编写第二个构造函数,允许注入dbCon,这允许我注入数据库连接的模拟版本,并针对public 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);
        }
    }
    
    MyClass
    现在更诚实地说明了执行所需功能所需的内容


    它还可以与模拟依赖项的注入隔离进行单元测试。

    您需要注入
    dbCon
    并测试
    doSomethingWith
    。“模拟的需要也是一种代码气味。”-如何、何处、谁?如果
    convertData
    不依赖于
    MyClass
    中的字段(即,是一个纯函数),那么将其设置为
    公共静态
    IMHO是无害的。Java在某种程度上迫使您进入“一切都必须是对象”的思维模式,远离那些非常适合单元测试的功能原则。您需要注入
    dbCon
    并测试
    doSomethingWith
    。“模拟的需要也是一种代码气味。”-如何、何处、谁?如果
    convertData
    不依赖于
    MyClass
    中的字段(即,是一个纯函数),那么将其设置为
    公共静态
    IMHO是无害的。Java在某种程度上迫使您进入“一切都必须是对象”的思维模式,远离那些非常适合单元测试的功能性原则。