Den*_*din 5 java spring microservices spring-cloud-feign openfeign
我已经实现了一个基于此官方存储库调用 get API 的 feign 客户端。我有一个规则类UserValidationRule,需要调用它来获取 API 调用getUser()并验证一些内容。这按预期工作,但是当我开始测试该规则类时,模拟假客户端并不成功,它会继续调用实际的 API。我已经简化了情况,所以请忽略简单性哈哈。这是我发现这个stackoverflow问题后的一个后续问题
API 返回此模型:
@Data
public class userModel {
private long id;
private String name;
private int age;
}
Run Code Online (Sandbox Code Playgroud)
与其余客户端方法的接口:
public interface UserServiceClient {
@RequestLine("GET /users/{id}")
UserModel getUser(@Param("id") int id);
}
Run Code Online (Sandbox Code Playgroud)
在规则类中,我构建了 feign 客户端并调用 API:
@RequiredArgsConstructor
@Component
public class UserValidationRule {
private static final String API_PATH = "http://localhost:8080";
private UserServiceClient userServiceClient;
public void validate(String userId, ...) {
// some validations
validateUser(userId);
}
private void validateUser(String userId) {
userServiceClient = getServiceClient();
UserModel userModel = userServiceClient.gerUser(userId);
// validate the user logic
}
}
private UserServiceClient getServiceClient() {
return Feign.builder()
.encoder(new GsonEncoder())
.decoder(new GsonDecoder())
.target(UserServiceClient.class, API_PATH);
}
}
Run Code Online (Sandbox Code Playgroud)
测试类来了:
public class UserValidationRuleTest {
private UserServiceClient userServiceClient = mock(UserServiceClient.class);
private UserValidationRule validationRule = new UserValidationRule();
private UserModel userModel;
@Before
public void init() {
userModel = generateUserModel();
}
@Test
public void validateWhenAgeIsNotBlank() {
doReturn(userModel).when(userServiceClient).getUser(any());
validationRule.validate("123", ...);
// some logic ...
assertEquals(.....);
verify(userServiceClient).getUser(any());
}
private UserModel generateUserModel() {
UserModel userModel = new UserModel();
userModel.setName("Cody");
userModel.setAge("22");
return accountModel;
}
}
Run Code Online (Sandbox Code Playgroud)
当我调试时validateWhenAgeIsNotBlank(),我发现 userModel 不是在测试类中生成的,并且值都是 null。如果我传入一个实际的userId,我会得到一个数据库中的实际 UserModel 。
我认为问题在于UserServiceClient没有被嘲笑。失败verify,因为它说getUser()未调用。这可能与 feign.builder() 中如何声明 feign 客户端有关UserValidationRule...如果我错了,请纠正我,并告诉我我缺少什么或有关如何正确模拟它的任何建议。
您没有使用 spring 管理的UserServiceClientbean。每次调用UserValidationRule.validate它时validateUser,都会调用该getServiceClient方法。这会为每次调用getServiceClient创建一个新实例UserServiceClient。这意味着在测试模拟时UserServiceClient根本没有被使用。
我将重构代码如下;
首先使用 声明UserServiceClient为最终版本@RequiredArgsConstructor或替换@RequiredArgsConstructor为@AllArgsConstructor。此更改的目的是允许UserServiceClient注入实例,而不是在服务方法内部创建实例。
@Component
@RequiredArgsConstructor
public class UserValidationRule {
private final UserServiceClient userServiceClient;
.... // service methods
}
Run Code Online (Sandbox Code Playgroud)
然后有一个单独的Configuration类,将 feign 客户端构建为 spring bean;
@Bean
private UserServiceClient userServiceClient() {
return Feign.builder()
.encoder(new GsonEncoder())
.decoder(new GsonDecoder())
.target(UserServiceClient.class, API_PATH);
}
Run Code Online (Sandbox Code Playgroud)
在运行时,该 bean 将被注入到UserValidationRule.
至于单元测试更改,您正在正确创建模拟,但没有在任何地方设置/注入该模拟。您需要使用@Mock注释@InjectMocks或手动创建UserValidationRule实例@Before。
这是如何@Mock和@InjectMocks使用应该是什么样子的;
@RunWith(MockitoJUnitRunner.class)
public class UserValidationRuleTest {
@Mock private UserServiceClient userServiceClient;
@InjectMocks private UserValidationRule validationRule;
... rest of the code
Run Code Online (Sandbox Code Playgroud)
或继续使用mock(...)方法并手动创建UserValidationRule.
public class UserValidationRuleTest {
private UserServiceClient userServiceClient = mock(UserServiceClient.class);
private UserValidationRule validationRule;
private UserModel userModel;
@Before
public void init() {
validationRule = new UserValidationRule(userServiceClient);
userModel = generateUserModel();
}
... rest of the code
Run Code Online (Sandbox Code Playgroud)
现在,这将确保您在运行时使用 spring 管理的 feign 客户端 bean 的单个实例,并使用模拟实例进行测试。
| 归档时间: |
|
| 查看次数: |
14718 次 |
| 最近记录: |