Java测试类中将对象属性插入List属性的实现是否存在隐患?
结论
你这段代码在当前单测试用例的场景下功能是正常的,但确实存在坏味道,且在特定写法下会触发隐蔽的BUG。
正常运行的逻辑前提
JUnit4的@Before注解方法会在每一个@Test方法执行前独立执行一次,也就是说每个测试用例拿到的object都是全新的实例,objects也是全新的空列表,你现在单独跑firstTest的逻辑是完全没问题的,断言也能正常通过。
存在的坏味道和潜在问题
- 同一个对象多次加入列表会出现联动修改BUG
Java集合的add方法存储的是对象引用,不是对象副本,如果你后续对同一个实例做属性修改,列表里所有指向该实例的引用对应的属性都会同步变更,比如下面的写法就会不符合预期:
@Test public void wrongTest() { object.setProperty("n1"); objects.add(object); object.setProperty("n2"); objects.add(object); // 预期两个元素属性分别是n1、n2,实际两个元素的属性都是n2 }
测试类全局变量的写法冗余且易出错
把object和objects抽成类属性完全没有必要:- 变量边界模糊,后续如果有人误删
@Before里的初始化逻辑,或者把@Before改成全局只执行一次的@BeforeClass,所有测试都会直接报错 - 读者需要额外向上查找变量初始化逻辑,增加代码理解成本
- 变量边界模糊,后续如果有人误删
当前断言写法存在语法缺陷
你写的assert(objects.get(0).getProperty().equals("n1");缺少右括号,而且裸用Java关键字assert的报错信息非常模糊,建议使用JUnit自带的断言方法比如assertEquals。
优化后的写法参考
public class TestingClass { @Test public void firstTest() { List<CustomObject> objects = new ArrayList<>(); CustomObject object = new CustomObject(); object.setProperty("n1"); objects.add(object); assertEquals("n1", objects.get(0).getProperty()); } // 多测试复用的初始化逻辑可以抽成私有工具方法 private CustomObject buildCustomObject(String property) { CustomObject obj = new CustomObject(); obj.setProperty(property); return obj; } @Test public void testAddMultipleObjects() { List<CustomObject> objects = new ArrayList<>(); objects.add(buildCustomObject("n1")); objects.add(buildCustomObject("n2")); assertEquals("n1", objects.get(0).getProperty()); assertEquals("n2", objects.get(1).getProperty()); } }
内容的提问来源于stack exchange,提问作者jpestana
相关产品推荐
相关产品推荐

