ユニットテストベストプラクティス例の概要


ユニットテストベストプラクティス例の概要


例1:不確定から確定になる


ビジネス


クーポンを一括発行する場合1 100 50 2 200 100 クーポンを一括作成してから一括発行する
for(CouponInfo info : couponInfoList){
        Coupon coupon = new Coupon();
        coupon.setCouponCode(UUIDGenerator.getUUID32()); //    84678bfd7c1011e6a22b4437e6d0648e
        // ...
        couponList.add(coupon);
}
couponService.batchAdd(couponList); // 

//  Map
 
couponService.batchSendCouponsToUser(userId, couponCodeCountMap); // 

に質問


クーポンの実際の発行状況をチェックしようとすると 200 1002枚発行した 100 501枚発行したが、クーポンコードはランダムに生成されており、ユニットテストで券とコードの対応関係を知ることができなかった.

解決する


クーポン符号化を生成する情報を独立した方法に抽出し、protected修飾を行い、サブクラスを上書きすることができる.以下に示す
protected String getUUID32(CouponInfo couponInfo) {
    return UUIDGenerator.getUUID32();
}

次に、ユニットテストで内部クラス継承テストするクラスを作成し、このメソッドを上書きします.
private static class MockBuyGiftsActivityService extends BuyGiftsActivityService{   
    @Override
    protected String getUUID32(CouponInfo couponInfo) {
            // couponCode   100_50
            return format("%d_%d",couponInfo.getReachPrice(),couponInfo.getCouponPrice()); 
        }
    }
}

ユニットテストでは
@InjectMocks
private MockBuyGiftsActivityService service; //  
 
//  
ArgumentCaptor> couponCodeCountMapCaptor = ArgumentCaptor.forClass(Map.class);
verify(couponService).batchSendCouponsToUser(eq(userId),couponCodeCountMapCaptor.capture());
Map couponCodeCountMap = couponCodeCountMapCaptor.getValue();
assertEquals(2, couponCodeCountMap.size()); //  
assertEquals(1, couponCodeCountMap.get("100_50").intValue()); //  100 50 1 
assertEquals(2, couponCodeCountMap.get("200_100").intValue()); //  200 100 2 

例2--Mockメソッドのオブジェクトパラメータ値の変更


ビジネス


同様の業務は注入couponCode統合couponServiceに過ぎない
//  couponList
for(CouponInfo info : couponInfoList){
        Coupon coupon = new Coupon();        
        // ...
        couponList.add(coupon);
}
couponService.batchAdd(couponList); // 

//  Map
 
couponService.batchSendCouponsToUser(userId, couponCodeCountMap); // 

に質問

couponService.batchAddcouponCode値注入
for(Coupon coupon : couponList){
        coupon.setCouponCode(UUIDGenerator.getUUID32()); //    84678bfd7c1011e6a22b4437e6d0648e
}

しかし、ユニットテストは実際にはmockメソッドの内部には入らない.
@Mock
private CouponService  couponService;

ユニットテストでcouponCodeが空になったため、後続の検証はできません.すべてのチケットのコードがNULLであるためです.

解決する


以下の解決方法を採用することができる
doAnswer(new Answer() {
    @Override
    public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
        List couponList = invocationOnMock.getArgumentAt(0, List.class); // artisanCouponModelList 
        couponList.get(0).setCouponId("100_50"); //  100 50 
        couponList.get(1).setCouponId("200_100"); //  200 100 
        return null;
    }
}).when(couponService).batchAdd(anyList());

ここでmockメソッドの対象パラメータを修正したことに相当し、後述する検証証券の発行状況が便利になった.
//  
ArgumentCaptor> couponCodeCountMapCaptor = ArgumentCaptor.forClass(Map.class);
verify(couponService).batchSendCouponsToUser(eq(userId),couponCodeCountMapCaptor.capture());
Map couponCodeCountMap = couponCodeCountMapCaptor.getValue();
assertEquals(2, couponCodeCountMap.size()); //  
assertEquals(1, couponCodeCountMap.get("100_50").intValue()); //  100 50 1 
assertEquals(2, couponCodeCountMap.get("200_100").intValue()); //  200 100 2