junit单元测试所踩到的坑

背景:某天,team内某童鞋叫我帮忙一起看个问题,原本运行正常的一个case(本人在一年前编写的),突然跑不过了,而且现象还非常诡异,搞了好久,不知道啥原因,严重影响移交进度(单测必须全过才能进行后续的发版流程)。

现象:1,本地跑单元测试能够全部通过(我们是直接执行gradle clean test),打个tag,一拿到单测服务器上跑,fail了

           2,单独跑这个fail的case,居然是成功的

我的第一反应,是不是改了啥,仔细一看,只是在这个case的java文件中加了一行打印日志,没有改动任何逻辑。再根据现象1发现本地机器和单测服务器的环境不同,本地是在windows操作系统下跑的单测,而服务器则是linux。赶紧换成linux的跑了下,fail,复现了这个现象。接下来,使用ide(idea) debug这个case,居然是成功的,现象诡异!没办法,只能按照操作步骤进行调试了。我们跑ut执行的命令是gradle test,debug下gradle的执行过程,然后在有问题的地方打上断点,提示有问题的代码如下:

@Service
public class P2PTransferDetailService {

    @Autowired
    private P2PTransferRequestsDAO transferRequestsDAO;
    
    ...
    
    
	@Transactional
	public void updateRequestAndHistory(P2PTransferRequestsDTO transferRequest) {
		P2PTransferRequestsHisDTO history = buildP2PTransferRequestsHis(transferRequest);
		transferRequestsHisDAO.insert(history);
		int count = transferRequestsDAO.updateIsProductCreated(transferRequest);//这里正常情况下应该不会有并发
		if(1!=count){
			throw new OptimisticLockException("update product created failed");
		}
		
	}
}

看下上面那个备注,ut跑了一整年,这里的count返回值都是1,且相关业务逻辑从未改动过。但是这次,这里的count返回0!!!,用ide单独debug这个case,count返回的值=1.这就是比较诡异的地方。我们debug下gradle test的执行过程,在if(1!=count)这个地方打个断点,执行一把,发现count的值确实为1,但是我们发现了一个问题transferRequestsDAO这个实例居然是由Mockito生成的(我们用Mockito这个工具对一些case进行mock),居然不是spring生成的实例:

问题就出在这里了!接下来我们需要找出P2PTransferDetailService中P2PTransferRequestDAO究竟是在哪个地方被替换掉了并且忘记还原。正常情况下被mock的对象在推出当前测试类的时候都会进行还原的,确保不能影响其他类的测试。经过查找代码,我们终于找到有问题的那段代码了:

public class P2PTransferDetailServiceTest {

    @InjectMocks
    @SpringBeanByType
    private P2PTransferDetailService p2PTransferDetailService;

    @MockObject(P2PTransferDetailService.class)
    @Mock
    private P2PTransferRequestsDAO transferRequestsDAO;
}

P2PTransferDetailService这个类被@InjectMocks,@SpringBeanByType标记,那么p2pTransferDetailService这个实例刚初始化时,其成员transferRequestsDAO会替换成Mockito生成的一实例(因为被@Mock标记了),spring容器中P2pTransferDetailService的实例中成员变量transferRequestsDAO就一直被更改了(没有被还原)。这样凡是UT跑在 上面这个case之后的ut,使用到P2pTransferDetailService中成员变量transferRequestsDAO的case都有可能失败!上面那个case失败就是这个原因,但是问题来了:为什么之前没有问题?猜测:本次加了一个日志,改变了ut执行时java文件的执行顺序。如何验证?还是debug下gradle clean test的执行过程,看下ut对应的类的执行顺序:

看上去,果然如此!那另一个问题来了,ut执行时究竟是根据什么规则进行读取的呢,读取出来的文件是根据什么规则进行排序的?或者没有排序规则?查了下相关资料,操作系统在读取某个目录下的所有文件时,不保证以特定的顺序返回,也不能保证它们按照文件名字母顺序返回。这个返回的顺序不同的操作系统间还有差异!这或许就能解释windows下ut是ok的,linux下不行。但是操作系统在读取目录下的文件时,到底默认是按照什么样的顺序返回呢?后续等自己搞明白后再来补充吧。。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值