簡體   English   中英

Mocking 一個 OpenFeign 客戶端,用於 spring 庫中的單元測試,而不是用於 spring 引導應用程序

[英]Mocking an OpenFeign client for Unit Testing in a spring library and NOT for a spring boot application

我已經實現了一個基於這個官方存儲庫調用 get API 的假客戶端。 我有一個規則 class UserValidationRule需要調用它來獲取 API 調用getUser()並驗證一些東西。 這按預期工作,但是當我開始測試該規則 class、mocking 時,偽裝客戶端不成功,它繼續調用實際的 API。 我已經簡化了情況,所以請忽略簡單性哈哈。 這是我發現這個stackoverflow問題后的后續問題

API 返回此 model:

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

在規則 class 中,我構建了 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);
    }
}

這里是測試 class:

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 不是在測試 class 中生成的,並且值都是 null。 如果我傳入一個實際的userId ,我會得到一個在我的數據庫中的實際 UserModel 。

我認為問題在於UserServiceClient沒有被嘲笑。 verify失敗,因為它表示未調用getUser() 這可能與如何使用 feign.builder() 在UserValidationRule中聲明 feign 客戶端有關...如果我錯了,請糾正我並告訴我我遺漏了什么或關於如何模擬它的任何建議正確。

您沒有使用 spring 托管的UserServiceClient bean。 每次調用UserValidationRule.validate時,它都會調用validateUser ,而后者又調用getServiceClient方法。 getServiceClient為每次調用創建一個新的UserServiceClient實例。 這意味着在測試模擬的UserServiceClient時根本沒有使用。

我將重組代碼如下;

首先使用@RequiredArgsConstructorUserServiceClient聲明為 final 或將@RequiredArgsConstructor替換為@AllArgsConstructor 此更改的目的是允許注入UserServiceClient的實例,而不是在服務方法內部創建。

@Component
@RequiredArgsConstructor
public class UserValidationRule {

    private final UserServiceClient userServiceClient;

.... // service methods

}

然后有一個單獨的Configuration class 將 feign 客戶端構建為 spring bean;

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

在運行時,這個 bean 現在將被注入到UserValidationRule中。

至於單元測試更改,您正在正確創建模擬,但沒有在任何地方設置/注入模擬。 您要么需要使用@Mock@InjectMocks注釋,要么在@Before方法中手動創建UserValidationRule的實例。

以下是@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 托管 feign 客戶端 bean 的單個實例和用於測試的模擬實例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM