hzdavid / jmockit.cn

JMockit中文网(jmockit.cn)上所有讲述的测试示例源代码
36 stars 15 forks source link

如何解决异步线程不生效的问题 #18

Open sfomp opened 5 years ago

sfomp commented 5 years ago

主线程中进行了mock静态方法,但是在主线程中待测试的代码中又启了新的线程,新的线程中也用到了前面mock的对象,但实际上获取不到值。这种情况如何解决。理论上jmockit也是用到了instrument的技术,内置的transformer生成的字节码会重新加载才对啊,对所有线程都是可用的。

@Before public void before() { message = new CacheMessage();

    byte[] msgByte = {1,2};
    message.setIsEncrypt(false);
    message.setMessageByte(msgByte);
    message.setStatus("15");
    message.setAppId(10000);
    message.setPushTime(1);
    message.setDataFrom(103);
    message.setPushType(1);
    message.setExpireTime(new Date(System.currentTimeMillis() + 1000000L));
    message.setMd5("");
    message.setMessageBizType(1);
    message.setMessageType(5);
    message.setAppType(1);

    clientInfo = getMockClientInfo(1L);

    new NonStrictExpectations(SpringUtils.class) {
        {
            SpringUtils.getBean("localCachePool");
            result = localCachePool;
            times = 10;

.....

@Test
public void testPublish() {

    PushServantImpl pushServant = new PushServantImpl();
    pushServant.sendByClientId(1, 1, PushType.ONE_REGID_PUSH.value);
}

pushServant里面有异步处理逻辑,异步的这句 localCachePool = SpringUtils.getBean("localCachePool");实际是取不值。

hzdavid commented 5 years ago

你是说localCachePool = SpringUtils.getBean("localCachePool") ,你拿的localCachePool为null?

sfomp commented 5 years ago

你是说localCachePool = SpringUtils.getBean("localCachePool") ,你拿的localCachePool为null? 是的,在Test类的当前线程里面是可以拿到 SpringUtils.getBean("localCachePool") 的实例,localCachePool已经通过Mocked注解。 @Mocked LocalCachePool localCachePool; 但是异步线程里面拿不到,理论上字节码会重新加载的。

sfomp commented 5 years ago

你是说localCachePool = SpringUtils.getBean("localCachePool") ,你拿的localCachePool为null? 是的,在Test类的当前线程里面是可以拿到 SpringUtils.getBean("localCachePool") 的实例,localCachePool已经通过Mocked注解。 @Mocked LocalCachePool localCachePool; 但是异步线程里面拿不到,理论上字节码会重新加载的。 另外的类,我通过反射给localCachePool设置一个自定义的filed,调试的时候发现可以看到这个filed,但是实际运行的时候不执行clientCache的createNewClientInfo方法,但是如果写成: LocalCachePool localCachePool = new LocalCachePool ();就可以 @Mocked LocalCachePool localCachePool;

比如: buildCache(); Field field = localClientCache.getClass().getDeclaredField("localClientCache"); field.setAccessible(true); field.set(localClientCache, clientCache); receiverToPusherServant.reportCtl(list); LocalClientInfo clientInfo1 = localClientCache.getClientInfo("1"); Assert.assertTrue("md5v".equals(clientInfo1.getControlInfo().getMd5Validity().get("md5"))); }

private void buildCache() {
    clientCache = Caffeine.newBuilder()
            .expireAfterAccess(1, TimeUnit.DAYS)
            .maximumSize(1)
            .build(clientId -> createNewClientInfo(clientId));
}

private LocalClientInfo createNewClientInfo(Long clientId) { return new LocalClientInfo(); }

hzdavid commented 5 years ago

@sfomp 异步线程 是通过jdk自带线程池启动的,还是直接new Thread