单元测试线上线下结果不一样,测试对象莫名多出$jacocodata属性

背景介绍

单元测试本地执行正常,但服务器上执行verify流水线就失败,原因是某个数字转换失败。
根据错误信息,跟踪到代码发现,转换异常的值是根据反射获取到对象的值信息,获取到值后进行数字转换异常了。但是该对象的属性都是数字类型,按道理不会有这种情况才是。

问题

  1. 为什么本地执行没有问题,而一上服务器执行单元测试就异常?
  2. mock对象的属性都是数字类型,且都赋了正常的值,为什么会转换失败?

排查

  1. 问题复现,找不同:服务器上通过maven命令执行的单元测试,而本地都是通过idea自带的junit插件执行的。本地换成mvn -Dtest命令执行发现果然出现异常了。
  2. 打印字段信息,发现使用mvn命令执行单元测试,mock对象中莫名其妙多了$jacocoData字段,是boolean[]类型的。而我们代码里面又是通过反射获取值,并转换成number类型,所以导致异常。
  3. 大概知道这个和jacoco代码覆盖率工具有关。使用idea的执行单元测试是idea自带的覆盖率工具。由于项目上maven引入了jacaca插件,用maven命令执行是使用了jacoco覆盖率插件。所以导致一开始线上线下执行的结果不一致。
  4. 对jacoco了解不深,大概是这个意思:为统计覆盖率jacoco在运行时修改字节码,给对象增加一个静态字段$ jacocoData。

解决

  1. 使用f
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 中,如果要使用 Mockito 来 mock 同一个对象属性中嵌套相同的对象多次,可以使用 `Answer` 接口来设置不同的返回值。具体来说,可以针对每个需要 mock 的对象设置一个返回值列表,然后在 `Answer` 的 `answer` 方法中使用这些列表来模拟多次调用返回不同的值。 举个例子,假设有以下的类和对象: ```java public class User { private String name; private int age; public User(String name, int age) { this.name = name; this.age = age; } // getter and setter methods } public class Group { private String name; private List<User> users; public Group(String name, List<User> users) { this.name = name; this.users = users; } // getter and setter methods } User user1 = new User("Alice", 20); User user2 = new User("Bob", 25); List<User> users = new ArrayList<User>(); users.add(user1); users.add(user2); Group group = new Group("Group1", users); ``` 那么在单元测试中,可以这样 mock 对象属性中嵌套相同的对象多次: ```java import static org.mockito.Mockito.*; public class TestMockito { @Test public void testMockNestedObjects() { User userMock1 = mock(User.class); User userMock2 = mock(User.class); Group groupMock = mock(Group.class); when(userMock1.getName()).thenReturn("AliceMock1"); when(userMock2.getName()).thenReturn("BobMock1"); when(groupMock.getName()).thenReturn("GroupMock1"); when(userMock1.getAge()).thenReturn(21); when(userMock2.getAge()).thenReturn(26); List<List<User>> usersList = new ArrayList<List<User>>(); usersList.add(Arrays.asList(userMock1, userMock2)); usersList.add(Arrays.asList(userMock2, userMock1)); when(groupMock.getUsers()).thenAnswer(new Answer<List<List<User>>>() { private int count = 0; @Override public List<List<User>> answer(InvocationOnMock invocation) throws Throwable { return usersList.get(count++); } }); assertEquals("AliceMock1", userMock1.getName()); assertEquals("BobMock1", userMock2.getName()); assertEquals("GroupMock1", groupMock.getName()); assertEquals(users, groupMock.getUsers()); when(userMock1.getName()).thenReturn("AliceMock2"); when(userMock2.getName()).thenReturn("BobMock2"); when(groupMock.getName()).thenReturn("GroupMock2"); assertEquals("AliceMock2", userMock1.getName()); assertEquals("BobMock2", userMock2.getName()); assertEquals("GroupMock2", groupMock.getName()); assertEquals(users, groupMock.getUsers()); } } ``` 在上面的测试函数中,我们使用 `mock` 函数创建了需要 mock 的对象,然后分别设置了它们的属性和返回值列表。在 `when` 中,我们使用了这些返回值列表来模拟多次调用返回不同的值。在 `groupMock.getUsers()` 中,我们使用了 `Answer` 接口来模拟多次调用返回不同的值。最后在测试中,我们分别测试了每次调用返回的值是否正确。 需要注意的是,在使用 `Answer` 接口时,我们需要在 `answer` 方法中记录当前调用的次数,并从返回值列表中取出相应的值返回,这样才能模拟多次调用返回不同的值。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值