繁体   English   中英

仅仅为了测试而使用额外的构造函数有多好?

[英]How good is it to use additional constructors just for testibility?

目前我需要编写SecondClass并决定使用这种解决方案编写,否则它将无法测试。

@Component
public class FirstClass {

    public void doStuff() {
        System.out.println("First Class stuff!");
    }

}

@Component
public class SecondClass {

    private final Random random;
    private final FirstClass firstClass;

    @Autowired
    public SecondClass(FirstClass firstClass) {
        this(new Random(), firstClass);
    }

    public SecondClass(Random random, FirstClass firstClass) {
        this.random = random;
        this.firstClass = firstClass;
    }

    public void doOtherStuff() {
        firstClass.doStuff();
        System.out.println("Second Class stuff " + random.nextInt(10));
    }

}

我的同事不喜欢我解决它的方式,喜欢这样的SecondClass实现:

@Component
public class SecondClass {

    private Random random;
    private final FirstClass firstClass;

    @Autowired
    public SecondClass(FirstClass firstClass) {
        this.random = new Random();
        this.firstClass = firstClass;
    }

    public void doOtherStuff() {
        firstClass.doStuff();
        System.out.println("Second Class stuff " + random.nextInt(10));
    }

    public void setRandom(Random random) {
        this.random = random;
    }

}

我不同意这种解决方案,因为我认为Random是这个类的必要部分,它不会在运行时更改,并且setter只是测试目的所必需的,这就是为什么我更喜欢带有两个构造函数的解决方案。

我们还想出了这种构造函数:

@Autowired(required = false)
public SecondClass(FirstClasss firstClass, Random random) {
    this.random = (random == null ? new Random() : random)
    ...
}

但实际上在构造函数中注入了更多的组件,因此如果需要所有这些组件将更为可取。

我很感兴趣,如果有人在此之前有这种经历吗? 您如何看待这种情况,以及是否有更好的方法来解决这个问题?

你的问题源于最后的领域。 跟随鲍勃叔叔,随意让他们受到保护,这样你就可以在测试课上给他们写信。 您不是在编写接口,而是在编写代码,因此访问修饰符并不重要,并且受保护很好,因为它允许包访问。

或者你可以通过硬连接将它们自己设置在你的测试用例中,比如ReflectionUtils.setField

如果在SecondClass声明了两个构造函数,并且只在单元测试中使用其中一个,则意味着单元测试的构造函数可以替换为单元测试的更相关技巧,例如反射以设置值。 random机场。
如果可以避免,则不应仅为单元测试打开API。
当您无法选择时,您应该打开您的API以进行单元测试。

如果在实例化SecondClass random字段是只读字段和已知值,则应该为SecondClass设置一个构造SecondClass random字段应该是final,并在SecondClass的构造函数中进行SecondClass

你是对的,我的朋友。 您的方法是正确的,因为根据面向对象的设计, 在执行任何构造函数之后必须将对象初始化为有效状态 因此,如果random字段是必需的, 则必须在所有构造函数中初始化它 此外,如果以后不再更改, 则必须是最终的 (并且没有制定者)。 所以第二种解决方案不正确,因为它违反了这一原则。

我不喜欢第三种解决方案,因为它对于客户端代码来说可能是愚蠢的:虽然客户端假定将null设置为输入值,但实际上使用了另一个(未受控制的)值。

所以,如果你需要一个构造函数SecondClass是testeable,去添加。 因为如果一个类不可测试, 它也不可执行 测试是确保类可用的正确方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM