【问题标题】:Unit testing class methods with private setters使用私有设置器对类方法进行单元测试
【发布时间】:2014-10-15 16:33:28
【问题描述】:

我是单元测试的新手,在这里遇到一个简单的用例。 我已将 setter 声明为私有(不希望任何人设置这些变量,除了 Spring)

private setX(T x) {
    this.x = x;
}

在编写单元测试时,我想为这些变量设置值,但我不能。一个快速的解决方法是拥有公共设置器,但这看起来不太好。我使用 Mockito 作为模拟框架,使用 Junit 进行单元测试。

感谢所有帮助。

编辑:

Class A {
    private Clazz clazz;
    //to be used only by spring
    private setClazz(Clazz clazz) {
        this.clazz = clazz;
    }

【问题讨论】:

    标签: junit mockito


    【解决方案1】:

    将它们设为受保护或包私有,并将测试与类放在同一个包中 正在测试中。

    或者像 Spring 那样使用反射来调用 setter。

    或者使用 Mockito 的 InjectMocks 注解,它会通过使用反射为您调用 setter 来注入模拟依赖项。

    【讨论】:

    • 任何关于此的cmets:tedvinke.wordpress.com/2014/02/13/…
    • 我同意其中一位评论者的观点:他实际上提倡的是使用字段和设置器注入,因为构造函数注入使依赖关系更加清晰。从哲学上讲,我同意他的观点。务实地说,我不同意,因为有一个构造函数初始化字段是样板代码,如果你认真对待 TDD,你应该在更新 bean 的同时更新测试,所以你不应该对 NullPointerException 感到惊讶。
    【解决方案2】:

    不要直接对私有成员进行单元测试。

    (整个互联网对此有很多争论。)

    单元测试不一定测试代码中的属性方法,它们测试的是代码的功能。具体来说,对象公开的面向外部的业务功能。因此,当您面对需要测试的私有成员时,以下两种情况之一是正确的:

    1. 业务功能可以根据状态调用该私有功能。因此,如果当前的单元测试没有调用该功能作为代码覆盖的一部分,那么这些测试并不详尽,并且存在未测试的状态。创建一个测试,在调用面向公众的功能之前安排该状态,以便间接测试该私有成员。
    2. 测试是详尽的,并且业务功能实际上不会在任何已知条件下调用该私有成员。在这种情况下,可以简单地从代码中删除该私有成员。

    面向对象设计的原则适用于单元测试,就像它们适用于任何其他代码一样。封装仍然是封装。如果单元测试强制打破该封装,那么它们很快就会与正在测试的代码紧密耦合,这会使它们变得更加脆弱。

    考虑red/green/refactor 循环的“重构”步骤。如果测试与被测试组件的私有内部紧密耦合,那么重构该组件将需要更改测试。不仅仅是重构这些测试,而是改变他们正在测试的逻辑。这打破了 TDD 循环。

    将其扩展为更大的代码系统,测试成为重构该代码的障碍,而它们应该成为重构该代码的资产。如果测试仅验证所产生的面向外部的功能,则可以轻松地重构代码的内部结构,并且可以使用测试来验证重构工作。

    【讨论】:

    • 我没有测试私有方法。我正在尝试设置私有变量(也有一个私有设置器)的值来测试其他公共函数。
    • @AmanDeepGautam:确实设置该私有成员的功能是什么?什么状态导致该私有成员被设置?我建议更深入地研究一下。避免紧密耦合的目标仍然存在。也许这里的阻塞问题不是测试无法安排必要的起始状态,而是需要更改对象以便更明确地允许达到该状态。 (如果不了解有关对象的更多信息,我不能肯定地说。)也许可以由测试注入的依赖项?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-30
    • 2021-12-07
    • 2010-09-20
    • 1970-01-01
    • 2020-12-03
    • 2018-02-01
    • 2018-08-01
    相关资源
    最近更新 更多