Java类静态方法的mock实现

Mockito 3.4.0

mock常见静态方法

待测试类:

package com.taobao.vip.shop.biz.sqyk.manager;

import com.taobao.vip.shop.biz.sqyk.util.TairUtil;

/**
 * Created by yitian.zyt on 2021/6/30
 */
@Slf4j
@Component
public class SqykChannelBenefitManager {
    public static final int BLACK_USER_TAIR_NAME_SPACE = 132;
    
    @Resource
    private TairManager blackUserTairManager;

    /**
     * 判断红包发放是否缓存记录
     * @param tairKey   缓存key
     * @return          有记录返回true,无记录返回false
     */
    public boolean isInWinPeriod(String tairKey) {
        String value = TairUtil.get(blackUserTairManager, BLACK_USER_TAIR_NAME_SPACE, tairKey);
        return StringUtils.isNotEmpty(value);
    }

}

测试方法:

package com.taobao.vip.shop.biz.sqyk.manager;

/**
 * Created by yitian.zyt on 2021/7/6
 */
@RunWith(MockitoJUnitRunner.class)
public class SqykChannelBenefitManagerTest extends TestCase {

    @InjectMocks
    private SqykChannelBenefitManager sqykChannelBenefitManager;

    @Mock
    private TairManager blackUserTairManager;

    @Before
    public void setup() throws NoSuchFieldException, IllegalAccessException {
        MockitoAnnotations.openMocks(this);
    }
    
    /**
     * isInWinPeriod
     */
    @Test
    public void isInWinPeriod_normalTest() {
        try (MockedStatic<TairUtil> theMock = Mockito.mockStatic(TairUtil.class)) {
            theMock.when(() -> TairUtil.get(blackUserTairManager, 132, "key")).thenReturn("hadWin");

            boolean res = sqykChannelBenefitManager.isInWinPeriod("key");
            Assert.assertTrue(res);
        }
    }

    @Test
    public void isInWinPeriod_nullTest() {
        try (MockedStatic<TairUtil> theMock = Mockito.mockStatic(TairUtil.class)) {
            theMock.when(() -> TairUtil.get(blackUserTairManager, 132, "key")).thenReturn(null);

            boolean res = sqykChannelBenefitManager.isInWinPeriod("key");
            Assert.assertFalse(res);
        }
    }
}

注意:上面TairUtil方法调用时传入的具体参数值,也可以使用Mockito.any形式进行替换。如果设置了具体参数,则仅能对具体参数的执行过程进行mock。

PowerMock

mock静态方法(带static代码块的类):

  1. PowerMock 抑制运行静态块:PowerMock 抑制运行静态块_千里之行始于足下-CSDN博客_powermock 抑制
  2. ProwerMock mock静态方法时,when...doReturn存在的bug:Static mocking broken for Mockito >= 2.26.1 · Issue #992 · powermock/powermock · GitHub
  3. bug使用when...doAnswer解决:android - org.mockito.exceptions.misusing.NotAMockException: Argument should be a mock, but is: class java.lang.Class for Andriod SSLContext.getInstance() metho - Stack Overflow

待测试类:

package com.taobao.vip.shop.biz.sqyk.domain.packageshow;

public class SqykPackageShowConfig {
    /**
     * 通用配置
     */
    private static Properties commonProperties;
    /**
     * 卡类别 -> 卡下所有权益
     */
    private static Map<String, List<SqykBenefitInfoWithClass>> cardClassIndex = Maps.newHashMap();
    
    // 类中存在静态代码块
    static {
        DiamondUtils.subscribe(BENEFIT_DATA_ID, GROUP_ID, x -> {
            if (StringUtils.isBlank(x)) {
                benefits = Lists.newArrayList();
            } else {
                benefits = JSON.parseArray(x, SqykBenefitInfoWithClass.class);
                buildIndex(benefits);
            }
        });

        DiamondUtils.subscribeByProperties(COMMON_DATA_ID, GROUP_ID, x -> {
            if (x == null) {
                commonProperties = new Properties();
            } else {
                commonProperties = x;
            }
        });
    }

    // 待测试静态方法
    public static List<SqykBenefitInfoWithClass> getBenefitsByCardClass(String cardClass) {
        List<SqykBenefitInfoWithClass> result = cardClassIndex.get(cardClass);
        return result == null ? new ArrayList<>(0) : result;
    }
}

测试方法:

package com.taobao.vip.shop.biz.sqyk.packageBenefit;

@RunWith(PowerMockRunner.class)
@PrepareForTest({SqykPackageShowConfig.class})
@SuppressStaticInitializationFor("com.taobao.vip.shop.biz.sqyk.domain.packageshow.SqykPackageShowConfig")
public class PackageBenefitOnActionCheckHandlerTest {
    private static final Long mockUserId=2210634737969L;
    private static final String mockLifeCycle="20210826-20210925";
    private static final String mockPackageName="crowd_pinHigh_taoLow_V6";
    private static final String mockBenefitCode="532e17d03653424893697dce7a60a21fxxxxxxx";
    private static final Long mockIssueRecordId= 12345678L;
    private static final String mockStrategyCode="42aff94fff074f3099836e0c844b25b0xxxxx";

    @Before
    public void setup() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void mockSqykPackageShowConfigGetBenefitsByCardClass(){
        List<SqykBenefitInfoWithClass> list = Lists.newArrayList();
        SqykBenefitInfoWithClass sqykBenefitInfoWithClass = new SqykBenefitInfoWithClass();
        sqykBenefitInfoWithClass.setBenefitCode(mockBenefitCode);
        sqykBenefitInfoWithClass.setBenefitClass("highValue");
        sqykBenefitInfoWithClass.setCardClass(mockPackageName);
        sqykBenefitInfoWithClass.setStrategyCode(mockStrategyCode);
        list.add(sqykBenefitInfoWithClass);
        
        // mockito无法mock带有static静态方法块的类
        //  try (MockedStatic<SqykPackageShowConfig> theMock = Mockito.mockStatic(SqykPackageShowConfig.class)) {
        //     theMock.when(()->SqykPackageShowConfig.getBenefitsByCardClass(mockPackageName)).thenReturn(list);
        //  }
        
        /*
        这里使用powermockito的如下方式有个bug:https://github.com/powermock/powermock/issues/992
        PowerMockito.when(SqykPackageShowConfig.getBenefitsByCardClass(mockPackageName)).thenReturn(list);
        需要使用when...thenAnswer的方式
         */
        PowerMockito.mockStatic(SqykPackageShowConfig.class);
        PowerMockito.when(SqykPackageShowConfig.getBenefitsByCardClass(mockPackageName)).thenAnswer(t -> list);
        List<SqykBenefitInfoWithClass> resultList = SqykPackageShowConfig.getBenefitsByCardClass(mockPackageName);
        Assert.assertNotNull(resultList);
    }
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值