簡體   English   中英

我可以在這種情況下編寫任何有意義的單元測試嗎?

[英]Can I write any meaningful unit test in this scenario?

我有這個實體 -

public class MerchantConfig {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private Long merchantId;
    private String configKey;
    private String configValue;
    ..
}

它目前在商家級別存儲配置(鍵和值)。

我們現在也需要在用戶級別(用戶到商家的一對多映射)存儲配置。

我們將這兩列添加到實體中 -

private Long entityId;
private String entityType;

entityId 現在將存儲merchantId/UserId,entityType 將與字符串值“merchantid”或“user_id”指示相同。

這是一個現有的服務層方法 -

public MerchantConfig enableSync(boolean isActive, Long merchantId,boolean isSync){
        MerchantConfig merchantConfig= merchantConfigRespository.findByMerchantIdAndConfigKey(merchantId,Constants.MerchantConfigKeys.SYNC_ENABLED.key);
        if(merchantConfig==null){
            merchantConfig = new MerchantConfig();
            merchantConfig.setMerchantId(merchantId);
            merchantConfig.setConfigKey(Constants.MerchantConfigKeys.SYNC_ENABLED.key);
        }
        if(isSync)
            merchantConfig.setConfigValue("1");
        else
            merchantConfig.setConfigValue("0");
        merchantConfig.setIsActive(isActive);
        return merchantConfigRespository.save(merchantConfig);
    }

這是上面的 controller -

@PostMapping("/admin/enableSync")
public ResponseEntity<Object> enableSync(HttpServletRequest request, HttpServletResponse response,
                                                  @RequestParam("merchantId") Long merchantId,
                                                  @RequestParam("isValid") boolean isValid,
                                                  @RequestParam("isSync") boolean isSync) {
    if (isValid && isSync)
        LOGGER.info("enabling sync for merchant {}", merchantId);
    else
        LOGGER.info("disabling sync for merchant {}", merchantId);

    MerchantConfig merchantConfig = merchantConfigService.enableSync(isValid, merchantId, isSync);
    if(merchantConfig!=null)
        return new ResponseEntity<>(new ResponseDTO(Constants.API_RESPONSE_SUCCESS, merchantConfig, "success"),
                HttpStatus.OK);
    return new ResponseEntity<>(new ResponseDTO(Constants.API_RESPONSE_FAILURE, "unable to enable sync"),
            HttpStatus.OK);
}

我們決定只更改服務並向下更改,保持 controller 層不變。

用服務方法中的 findByEntityIdAndEntityTypeAndConfigKey() 替換存儲庫方法調用 findByMerchantIdAndConfigKey() 並進行此更改 -

public MerchantConfig enableSync(boolean isActive, Long merchantId,boolean isSync){
    MerchantConfig merchantConfig= merchantConfigRespository.findByEntityIdAndEntityTypeAndConfigKey(merchantId,Enum.MerchantConfigType.MERCHANT_ID.v,Constants.MerchantConfigKeys.SYNC_ENABLED.key);
    if(merchantConfig==null){
        merchantConfig = new MerchantConfig();
        merchantConfig.setEntityId(merchantId);
        merchantConfig.setEntityType(Enum.MerchantConfigType.MERCHANT_ID.v);
        merchantConfig.setConfigKey(Constants.MerchantConfigKeys.SYNC_ENABLED.key);
    }
    if(isSync)
        merchantConfig.setConfigValue("1");
    else
        merchantConfig.setConfigValue("0");
    merchantConfig.setIsActive(isActive);
    return merchantConfigRespository.save(merchantConfig);
}

我在服務層放了什么有用的單元測試用例?

如果我要模擬存儲庫層響應並驗證 servive 方法是否返回與模擬響應相同的 MerchantConfig 實體,這不是矯枉過正嗎?

相反,我覺得測試 db 值會更有用,方法是在 db 中創建一些已知條目。 例如,在這種情況下,當 db 中已經有一些商家級別的配置並且要輸入用戶級別的配置時,應該覆蓋用戶級別的條目,因為配置器正在嘗試取消設置所有商家級別的配置。

測試是否在 db 中給定商家級別的配置會很有用,當調用保存配置 API 端點來保存用戶級別的配置時,商家級別的配置被標記為非活動狀態。

順便問一下,這些測試叫什么? 請給出一些解決方案,因為我已經在這場辯論中苦苦掙扎了一段時間。 每次坐下來寫傳統的單元測試用例,我都花太多時間,還是有問題,這是單元測試無法覆蓋的。 請提供一些全面的指南來編寫此類測試。

首先,感謝您的提問,這是一個很好的問題。 這讓我思考。 現在關於答案...

如果有任何科學證明是編寫測試的唯一正確方法,我不知道 作為專業人士,您將不得不撥打電話。 如果我是你,我會考慮以下幾點:

  • 為幾行更改編寫單元測試確實看起來有點矯枉過正。 很容易想象如何使用 mocking 完成 30 行單元測試來僅測試幾行更改。 讓它成為選項1。
  • 另一方面,使用 DB 編寫集成測試(為了測試,可能在內存中)現在看起來可能是一個簡單的解決方案。 讓它成為選項2。

選項 1我使用的經驗法則是,如果某些東西可以通過單元測試進行測試,那么它應該通過單元測試進行測試,除非我有充分的理由不這么認為。 這是我個人的選擇,原因如下:

  • 速度。 單元測試總是更快地運行和調試(即使它們編寫的時間更長)
  • 粒度。 通過單元測試,我幾乎總能知道問題出在哪里。

選項 2現在,在我看來,使用集成測試而不是單元測試的唯一正當理由是某些東西非常難以/不可能以其他方式進行測試。 只有當我完全確定這部分邏輯永遠不會再改變時,我可能會在你的情況下選擇這個,但我認為情況並非如此。

現在我們可以提出選項 3 :它確實看起來像enableSync對許多事情所做的(即創建/查找 object 並切換同步標志)

如果您將下面的代碼提取到一個單獨的方法中(比如說,構建merchantConfig ):

 MerchantConfig merchantConfig= 
    if(merchantConfig==null){
        merchantConfig = new MerchantConfig();
        merchantConfig.setEntityId(merchantId);
        merchantConfig.setEntityType(Enum.MerchantConfigType.MERCHANT_ID.v);
        merchantConfig.setConfigKey(Constants.MerchantConfigKeys.SYNC_ENABLED.key);
    }

這應該很容易進行單元測試,並且不需要數據庫交互或 mocking。

暫無
暫無

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

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