java—模拟openfeign客户机在spring库中进行单元测试,而不是在spring引导应用程序中进行单元测试

1tu0hz3e  于 2021-07-16  发布在  Java
关注(0)|答案(1)|浏览(552)

我已经实现了一个基于这个官方存储库调用getapi的假客户机。我有一节规则课 UserValidationRule 需要调用get api调用 getUser() 验证一些东西。这和预期的一样有效,但是当我开始测试这个规则类时,模仿外部客户机并不成功,它会继续调用实际的api。我已经简化了情况,所以请忽略简单lol。这是一个后续问题,我发现这个问题
api返回此模型:

@Data
public class userModel {
    private long id;
    private String name;
    private int age;

}

与rest客户端方法的接口:

public interface UserServiceClient {

    @RequestLine("GET /users/{id}")
    UserModel getUser(@Param("id") int id);
}

在rule类中,我构建了假客户端并调用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);
    }
}

接下来是测试课:

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;
    }
}

当我调试时 validateWhenAgeIsNotBlank() ,我看到usermodel不是在test类中生成的,并且值都是null。如果我通过一个真实的 userId ,我得到了数据库中的实际用户模型。
我想问题是 UserServiceClient 不是被嘲笑。这个 verify 就像上面说的 getUser() 未调用。这可能与在 UserValidationRule 使用feign.builder()。。。请纠正我,如果我错了,告诉我我错过了什么或任何建议,如何嘲笑它正确。

gpnt7bae

gpnt7bae1#

您没有使用Spring UserServiceClient 豆子。每次你打电话 UserValidationRule.validate 它叫 validateUser 这又称为 getServiceClient 方法。这个 getServiceClient 创建的新示例 UserServiceClient 每次调用。这意味着在测试模拟的 UserServiceClient 根本不用。
我将重组代码如下;
先声明 UserServiceClient 作为最终的 @RequiredArgsConstructor 或替换 @RequiredArgsConstructor@AllArgsConstructor . 此更改的目的是允许 UserServiceClient 而不是在服务方法内部创建。

@Component
@RequiredArgsConstructor
public class UserValidationRule {

    private final UserServiceClient userServiceClient;

.... // service methods

}

那就单独谈谈 Configuration 作为Springbean构建外部客户机的类;

@Bean
private UserServiceClient userServiceClient() {
       return Feign.builder()
              .encoder(new GsonEncoder())
              .decoder(new GsonDecoder())
              .target(UserServiceClient.class, API_PATH);
}

在运行时,这个bean现在将被注入到 UserValidationRule .
至于单元测试更改,您正在正确地创建mock,但是没有在任何地方设置/注入该mock。你要么用 @Mock 以及 @InjectMocks 注解或手动创建的示例 UserValidationRule 在你的 @Before 方法。
这里是如何 @Mock 以及 @InjectMocks 使用应该像;

@RunWith(MockitoJUnitRunner.class)
public class UserValidationRuleTest {

    @Mock private UserServiceClient userServiceClient;
    @InjectMocks private UserValidationRule validationRule;
    ... rest of the code

或继续使用 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

这将确保您在运行时使用spring管理的外部客户机bean的单个示例和模拟示例进行测试。

相关问题