mockito 调用Java中的私有方法和其他对象的单元测试公共方法

r6vfmomb  于 2022-11-08  发布在  Java
关注(0)|答案(3)|浏览(540)

我是单元测试的新手,最近尝试了JUnit测试和Mockito。
我正在尝试对一个调用多个私有方法并创建其他类的私有对象的方法进行单元测试。
如何对方法进行单元测试。
下面是一个例子:

class ClassToTest {
    private OuterClass outerClass;
    public Boolean function() {
        outerClass = new OuterClass(20);
        return innerFunction(outerClass.getValue());
    }

    private Boolean innerFunction(int val) {
        if (val % 2 == 0)
            return true;
        return false;
    }
}

我很困惑如何测试公共函数。

d4so4syb

d4so4syb1#

方法如何实现并不重要;这个方法应该有一个它所遵守的契约,并且 that 是你要用测试来验证的。在这个例子中,如果outerClass的值是偶数,function()应该返回true。实现这个的一个方法是注入(传递到ClassToTest构造函数中)outerClass的示例,这样你就可以在测试时控制这个值:

@Test
public void trueWhenEven() {
    var outer = new OuterClass(2);
    var ctt = new ClassToTest(outer);
    assertTrue(ctt.function());
}

有时候契约只是一个方法调用其他一些对象上的方法;在这些情况下,你可以使用Mockito或类似的库来验证交互。

ibrsph3r

ibrsph3r2#

您将直接从一些重要的问题开始单元测试。

  • 问题1:如何处理实施细节/私有函数?* 答案:单元测试是关于发现代码中的错误,这是单元测试的一个主要目标(以及大多数其他类型的测试)。另一个主要目标是通过在软件更改时充当回归测试来防止引入bug。bug存在于实现中-不同的实现伴随着不同的bug。因此,确保测试实现的细节。这里支持的一个重要工具是覆盖率分析,它显示测试已经达到了实现代码的哪些部分。

您甚至可以测试函数契约之外的方面:a)否定测试是有意检查无效/未指定输入行为的测试,对于确保系统安全非常重要。因为,即使提供了无效输入,系统也不应允许因读取或写入超出界限的内存等原因而受到攻击。然而,这可能不适用于您的示例,因为您的方法很可能被指定实现一个“total函数”而不是“partial函数”。b)实现细节的测试(如果可访问的话)甚至可以在当前实现所需的范围之外执行。这样做可以防止对组件的即将到来的更改中的bug,例如,API的扩展。
然而,单元测试还有次要的目标。其中之一是避免当实现细节改变时,你的测试不必要地中断。达到次要目标的一个方法是,通过公共API测试实现细节。这样,实现细节的某些类型的重新设计将不会中断你的测试:私有函数的重命名、拆分或合并不会影响测试。但是,切换到不同的算法可能需要重新考虑测试:斐波纳契函数的迭代/递归实现的测试看起来与使用Moivre/Binet的封闭形式表达式的实现或查找表实现的测试不同。
对于您的示例,这意味着您应该尝试通过公共API测试私有函数的功能。

  • 问题2:如何处理与软件其他部分的依赖关系?* 单元测试的重点是在小的、孤立的代码片段中查找bug。当这些代码片段与其他代码部分存在依赖关系时,这可能会对您正确地进行单元测试的能力产生负面影响。但是否确实如此取决于实际的依赖关系。例如,如果您的代码使用了Math.sin()函数,这也是对不同代码部分的依赖,但是这样的依赖通常不会损害您正确测试代码的能力。

在下列情况下,与其他元件的相依性会让您感到困扰:使用其他组件使得在测试代码中模拟所有感兴趣的场景变得困难。或者,使用其他组件导致不确定性行为(时间、随机性等)。或者,使用其他组件导致生成或执行时间过长。或者,其他组件有缺陷或甚至不可用。
如果所有这些条件都不满足(Math.sin()函数通常就是这种情况),你通常可以将其他组件作为测试的一部分。但是,你应该记住,在单元测试中,你仍然关注代码中的bug,而不是开始编写实际测试其他组件的测试:请记住,其他组件有自己的测试。
在你的例子中,你选择了Outerclass来拥有一些看起来微不足道的功能。在这种情况下,你可以使用Outerclass作为测试的一部分。然而,这只是你的一个例子--根据上面的标准,真正的其他类实际上可能是令人不安的。如果是这样的话,那么你就不得不设法管理这个依赖关系。这些都要求以某种方式实现测试友好的设计。
这里有一个完整的方法家族,所以你最好在网上搜索“可测试性设计”和“控制反转”。而且,你也应该尝试学习单元测试和集成测试的区别:这将帮助您避免尝试在应该用集成测试来测试的代码部分上应用单元测试。

6ojccjat

6ojccjat3#

通常,使用Mockito时,这需要使用依赖注入,然后您将为测试注入一个OuterClass的模拟。
如果您真的想在不添加Spring类型框架的情况下进行测试,我可以想到3个选项:
1)将其作为集成测试,并测试所有内容的真实示例
2)修改代码,以便通过setter或构造函数传入的Object创建OuterClass,然后为测试传入一个mock
3)将private OuterClass outerClass;更改为protected OuterClass outerClass;,并确保您的测试包结构与实际代码包结构相同,然后您可以在测试设置中执行outerClass = Mockito.mock(OuterClass);

相关问题