正确使用“构造函数注入” - 如何处理调用类中的依赖关系?

问题描述 投票:0回答:1

我想知道我在使用“构造函数注入”时是否思维错误:

给定两个规则,它们具有完全不同的任务和要使用的依赖关系。

为了使它们可进行单元测试,我通过构造函数注入这些依赖项。

class RuleA implements MyInterface {

 private DependencyA_1 dependencyA1;
 private DependencyA_2 dependencyA2;

 public RuleA(DependencyA_1 dependencyA1, DependencyA_2 dependencyA2) {
    this.dependencyA1 = dependencyA1;
    this.dependencyA2 = dependencyA2;
}

 public Result execute() {
....
}
class RuleB implements MyInterface {

 private DependencyB_1 dependencyB1;
 private DependencyB_2 dependencyB2;

 public RuleB(DependencyB_1 dependencyB1, DependencyB_2 dependencyB2) {
    this.dependencyB1 = dependencyB1;
    this.dependencyB2 = dependencyB2;
}

 public Result execute() {
....
}

仅给定一个字符串(例如,来自数据库结果)来创建正确的规则,我为实例化创建一个工厂。

但是如果我这样做,我的工厂需要知道我所有规则的每个依赖项(在我看来)这是一个很大的耦合问题,如果我想对我的工厂进行单元测试,我需要模拟所有这些依赖项,这我的工厂不应该知道。

因此,对于生产代码,我将向 RuleA 和 RuleB 添加无参构造函数,其中“真实”对象被实例化,如下所示:

 public RuleA(DependencyA_1 dependencyA1, DependencyA_2 dependencyA2) {
    this.dependencyA1 = dependencyA1;
    this.dependencyA2 = dependencyA2;
}

public RuleA() {
    this(new MyProductiveDependencyA1(), new MyProductiveDependencyA2());
}

....
class Factory {

  public MyInterface createClass(String type) {
     if ("A".equals(type)) {
         return new RuleA();
     }

     if ("B".equals(type)) {
         return new RuleB();
     }

}

但是现在我的工厂或任何其他使用它的类不可进行单元测试,因为使用 RuleA 和 RuleB 的生产构造函数可能需要正在运行的数据库或任何外部模块。

所以我的问题是:

使用一个构造函数进行单元测试,使用另一个构造函数进行“正常/生产”使用(当然,如果其中没有逻辑),这是一种很好的模式吗? 如果我在调用类中使用单元测试构造函数,他们需要知道被调用类的所有依赖关系,并且当考虑更深的层次结构时,这可能会变得非常混乱。如果我使用非参数构造函数,则调用类不可进行单元测试。我该怎么办?我是否需要接受这些类只能在集成测试中进行测试,或者这是一种糟糕的软件设计的味道?

我知道有几个使用注释的依赖注入框架,因此我可以模拟所需的依赖项,而无需通过构造函数传递它们,但如果可能的话,我想避免它们。

java unit-testing dependency-injection integration-testing
1个回答
0
投票

问。使用一个构造函数进行单元测试,使用另一个构造函数进行“正常/生产”使用(当然,如果其中没有逻辑),这是一种很好的模式吗?

A.不,这根本不是一个好的做法。事实上,使用不同的构造函数进行测试和生产通常表明存在设计问题。

最简单的解决方案之一是在更高级别包装依赖项并在 Factory 中使用新类。 不要直接在工厂中创建 RuleA 和 RuleB,而是在工厂内使用依赖注入器,这样工厂就不会知道依赖关系:

class Factory {
    public MyInterface createClass(String type) {
        if ("A".equals(type)) {
            return Injector.createRuleA();
        }
        if ("B".equals(type)) {
            return Injector.createRuleB();
        }
        throw new IllegalArgumentException("Unknown type: " + type);
    }
}

class Injector {
    public static RuleA createRuleA() {
        return new RuleA(new DependencyA_1(), new DependencyA_2());
    }

    public static RuleB createRuleB() {
        return new RuleB(new DependencyB_1(), new DependencyB_2());
    }
}

在单元测试期间模拟接口依赖关系。

© www.soinside.com 2019 - 2024. All rights reserved.