如何在 Spring Boot with JUnit 中模拟 public 方法中的私有方法
How to mock private method in public method in Spring Boot with JUnit
请教您几个问题,请教您:
我想测试我的 public 方法(我使用 Spring Boot、Mockito、JUnit):
@Service
public class MyClass{
public Long getClientId(List<String> nameSurname) throws AuthorizationException {
Long operatorId;
if(...){
(... something not interesting ...)
User user = getUserByLogin("AnthonyGates2");
operatorId = nonNull(user) ? user.getOperatorId() : null;
} else {
List<User> users = getUserListByLogin("AnthinyGates");
operatorId = isNotEmpty(users) ? return operatorId;
return operatorId;
}
如何测试方法getClientId
?
方法 getUserByLogin
和 getUserListByLogin
在此 class (MyClass
) 中是私有的,但我必须模拟这些私有方法的结果,因为这些方法从外部服务。
这些私有方法如下所示:
User user = DelegateImpl.getDelegate().getUserByLogin(nameAndSurname);
DelegateImpl.getDelegate().getUserByLogin 从数据库中获取数据并且必须像这样模拟数据:
when(DelegateImpl.getDelegate().getUserByLogin(any())).thenReturn(user);
如何测试我的 public class?我应该使用 PowerMock/PowerMockito 吗?在我看来,使这些方法 public 很难看,因为这些方法仅在 MyClass
中调用。我无法在 Internet 上为我的案例找到好的教程(Spring Boot、Mockito、JUnit)。
非常感谢您的所有提示!
此致
马修
如果您无法对 method/class 进行单元测试,那么很可能意味着它做的太多了。尝试将您的私有方法提取到单独的 class。它不需要是 public - 你可以,例如将它放在同一个包中。
稍后,在测试中,您必须注入此 class 的模拟并模拟其行为。
MyClass 在其单元测试中的设置可能与此类似:
AnotherClass anotherClassMock = Mockito.mock(AnotherClass.class);
MyClass myClass = new MyClass(anotherClassMock);
AnotherClass 有方法 getUserListByLogin 和 getUserByLogin。
编辑:
您的私有方法中的逻辑似乎已经调用了外部 class。问题是您通过调用另一个 class.
中的静态 getDelegate()
方法来获取对象的实例
您可以执行以下操作:
- 在
MyClass
中创建一个与 getDelegate()
方法返回的类型相同的新字段(我不知道那是什么,我将其称为 Delegate
)
- 有 2 个构造函数:一个默认构造函数会将
getDelegate
方法的结果分配给您的新字段,另一个构造函数会将 Delegate
的实例作为参数并将其分配给您的字段
- 在测试中使用第二个构造函数创建
MyClass
的实例并传递 Delegate
class 的模拟
它看起来或多或少像这样:
class MyClass() {
private Delegate delegate;
MyClass() {
this.delegate = DelegateImpl.getDelegate();
}
MyClass(Delegate delegate) {
this.delegate = delegate;
}
// ... the rest
}
仅通过调用 public 方法测试单元。我认为您的示例是服务层中的 class (包含业务逻辑),并且两个 getUser... 方法应该位于不同的 class (我认为在数据层中)它们可以是 public。通过构造函数将 class 作为依赖项注入(在服务对象中),这样您就可以在测试服务 class 时模拟它。数据层 class(使用 getUser... 方法)也可以通过它自己的单元测试进行测试。
请教您几个问题,请教您:
我想测试我的 public 方法(我使用 Spring Boot、Mockito、JUnit):
@Service
public class MyClass{
public Long getClientId(List<String> nameSurname) throws AuthorizationException {
Long operatorId;
if(...){
(... something not interesting ...)
User user = getUserByLogin("AnthonyGates2");
operatorId = nonNull(user) ? user.getOperatorId() : null;
} else {
List<User> users = getUserListByLogin("AnthinyGates");
operatorId = isNotEmpty(users) ? return operatorId;
return operatorId;
}
如何测试方法getClientId
?
方法 getUserByLogin
和 getUserListByLogin
在此 class (MyClass
) 中是私有的,但我必须模拟这些私有方法的结果,因为这些方法从外部服务。
这些私有方法如下所示:
User user = DelegateImpl.getDelegate().getUserByLogin(nameAndSurname);
DelegateImpl.getDelegate().getUserByLogin 从数据库中获取数据并且必须像这样模拟数据:
when(DelegateImpl.getDelegate().getUserByLogin(any())).thenReturn(user);
如何测试我的 public class?我应该使用 PowerMock/PowerMockito 吗?在我看来,使这些方法 public 很难看,因为这些方法仅在 MyClass
中调用。我无法在 Internet 上为我的案例找到好的教程(Spring Boot、Mockito、JUnit)。
非常感谢您的所有提示!
此致 马修
如果您无法对 method/class 进行单元测试,那么很可能意味着它做的太多了。尝试将您的私有方法提取到单独的 class。它不需要是 public - 你可以,例如将它放在同一个包中。
稍后,在测试中,您必须注入此 class 的模拟并模拟其行为。
MyClass 在其单元测试中的设置可能与此类似:
AnotherClass anotherClassMock = Mockito.mock(AnotherClass.class);
MyClass myClass = new MyClass(anotherClassMock);
AnotherClass 有方法 getUserListByLogin 和 getUserByLogin。
编辑: 您的私有方法中的逻辑似乎已经调用了外部 class。问题是您通过调用另一个 class.
中的静态getDelegate()
方法来获取对象的实例
您可以执行以下操作:
- 在
MyClass
中创建一个与getDelegate()
方法返回的类型相同的新字段(我不知道那是什么,我将其称为Delegate
) - 有 2 个构造函数:一个默认构造函数会将
getDelegate
方法的结果分配给您的新字段,另一个构造函数会将Delegate
的实例作为参数并将其分配给您的字段 - 在测试中使用第二个构造函数创建
MyClass
的实例并传递Delegate
class 的模拟
它看起来或多或少像这样:
class MyClass() {
private Delegate delegate;
MyClass() {
this.delegate = DelegateImpl.getDelegate();
}
MyClass(Delegate delegate) {
this.delegate = delegate;
}
// ... the rest
}
仅通过调用 public 方法测试单元。我认为您的示例是服务层中的 class (包含业务逻辑),并且两个 getUser... 方法应该位于不同的 class (我认为在数据层中)它们可以是 public。通过构造函数将 class 作为依赖项注入(在服务对象中),这样您就可以在测试服务 class 时模拟它。数据层 class(使用 getUser... 方法)也可以通过它自己的单元测试进行测试。