【发布时间】:2019-11-22 10:24:38
【问题描述】:
我已经为静态方法编写了一些单元测试。静态方法只接受一个参数。参数的类型是最终类。代码方面:
public class Utility {
public static Optional<String> getName(Customer customer) {
// method's body.
}
}
public final class Customer {
// class definition
}
所以对于Utility 类,我创建了一个测试类UtilityTests,我在其中为此方法编写了测试,getName。单元测试框架是TestNG,使用的模拟库是Mockito。所以一个典型的测试有以下结构:
public class UtilityTests {
@Test
public void getNameTest() {
// Arrange
Customer customerMock = Mockito.mock(Customer.class);
Mockito.when(...).thenReturn(...);
// Act
Optional<String> name = Utility.getName(customerMock);
// Assert
Assert.assertTrue(...);
}
}
有什么问题?
虽然测试在 IntelliJ 中在本地成功运行,但在 Jenkins 上却失败了(当我将代码推送到远程分支时,会触发构建并在最后运行单元测试)。错误信息如下:
org.mockito.exceptions.base.MockitoException:无法模拟/监视类 com.packagename.Customer Mockito 不能模拟/间谍,因为: - 最后一课
我尝试了什么?
我搜索了一下,以找到解决方案,但我没有成功。我在这里指出,我不允许更改 Customer 是 final 类的事实。除此之外,如果可能的话,我希望不完全改变它的设计(例如,创建一个接口,它将包含我想要模拟的方法并声明 Customer 类实现了该接口,正如何塞在他的评论中正确指出的那样)。我尝试的是mockito-final 中提到的第二个选项。尽管这解决了问题,但它阻止了其他一些单元测试:(,无法以明显的方式修复。
问题
所以这是我的两个问题:
- 首先这怎么可能?测试不应该在本地和詹金斯都失败吗?
- 如何根据我上面提到的约束来解决这个问题?
提前感谢您的帮助。
【问题讨论】:
-
我的猜测是
enable final配置在您的工作区中有效,但在Jenkins上运行时无法找到此文件。检查Jenkins在哪里查找文件以及它是否确实存在。 -
另一个线程解释了如何在 Mockito 2 中启用最终类模拟,方法是在资源目录下添加一个 mockito 配置文件:stackoverflow.com/questions/14292863/…
-
在您处理的代码中,是否有可能从 Customer 类中提取一个接口,比如 ICustomer,并在 Utility 类中使用它?然后你可以模拟那个接口而不是具体的最终类
-
@JoseTepedino 这是一个有效的观点。它确实完全有意义,并且绝对是克服这个问题的一种优雅方法。但是我想知道是否有另一种方法,更重要的是,我想了解为什么当前方法在本地成功而在 Jenkins 中失败。
-
Customer中是否有任何逻辑,或者它只是一个愚蠢的数据类?如果它只是一堆带有 getter 和 setter 的字段,那么你可以实例化它。
标签: java unit-testing mockito testng