如何最优单元测试MultiplierUser的setResult方法?两种方案该选哪一个?
问题分析与解答
先整理你提供的两个类代码:
Multiplier类
public class Multiplier { private static Map<Integer, Float> map; private static final float DEFAULT_MULTIPLIER = 4.4F; static { // This map is actually populated by reading from a file. This is an example on how the map looks like. map = new HashMap<>(); map.put(1, 3.5F); // 注:原代码中写的是字符串"3.5F",属于笔误,实际应为float类型值 map.put(2, 5.8F); map.put(3, 2.7F); } public static float getMultiplier(Integer id) { return map.getOrDefault(id, DEFAULT_MULTIPLIER); } }
MultiplierUser类
public class MultiplierUser { private Integer id; private float value; private float result; public MultiplierUser(int id, float value) { this.id = id; this.value = value; } public void setResult() { result = value * Multiplier.getMultiplier(this.id); } public float getResult() { return this.result; } }
关于setResult()单元测试的最优方案
你困惑的核心是没理清单元测试的职责边界:单元测试要聚焦单一类/方法的逻辑,不能把依赖类的逻辑混进来。
第一种方式的问题
你写的第一个测试代码:
public testMethod() { MultiplierUser multiplierUser = new MultiplierUser(1, 10F); multiplierUser.setResult(); float expected = Multiplier.getMultiplier(1) * 10F; Assert.assertEquals(expected, multiplierUser.getResult()); }
这种方式完全不可取,原因有两点:
- 把Multiplier的逻辑绑定到了MultiplierUser的测试中——如果Multiplier的
getMultiplier()出bug(比如返回错误值),这个测试会失败,但其实MultiplierUser的计算逻辑是正确的,属于误判。 - 如果MultiplierUser的逻辑写错了(比如把乘法改成加法),因为预期值也依赖同一个Multiplier方法,结果会跟着出错,测试会错误通过,等于漏掉了自身的bug。
第二种方式的修正与正确用法
你想到的Mock思路是对的,但要注意:Multiplier的getMultiplier()是静态方法,普通Mockito.mock无法mock静态方法,需要用Mockito.mockStatic(Mockito 3.4+版本支持)。正确的测试代码如下:
@Test void testSetResult() { // 1. 创建测试对象 MultiplierUser user = new MultiplierUser(1, 10F); // 2. Mock Multiplier类的静态方法,指定传入id=1时返回1.5F try (MockedStatic<Multiplier> mockedMultiplier = Mockito.mockStatic(Multiplier.class)) { mockedMultiplier.when(() -> Multiplier.getMultiplier(1)).thenReturn(1.5F); // 3. 执行要测试的方法 user.setResult(); // 4. 计算预期值并断言(浮点数断言需加精度容差) float expected = 10F * 1.5F; Assert.assertEquals(expected, user.getResult(), 0.001); } }
这种方式的优势:
- 完全隔离依赖:不管Multiplier的逻辑是什么,我们强制让它返回已知固定值,测试只验证MultiplierUser是否正确执行了
value * 乘数的计算逻辑。 - 可覆盖所有分支:比如测试id不存在的情况,Mock返回
DEFAULT_MULTIPLIER,验证计算是否正确;测试不同的value和乘数组合,确保乘法逻辑无问题。
补充说明
- Multiplier类的
getMultiplier()方法,需要单独写单元测试,验证它的逻辑:比如正确id返回对应值、不存在的id返回默认值、文件加载的映射是否正确等——这是Multiplier自身的测试范围,和MultiplierUser无关。 - 浮点数断言必须加精度容差(比如
0.001),因为浮点数计算可能存在精度误差,直接判断相等会导致测试无意义地失败。
内容的提问来源于stack exchange,提问作者Gengis Khan
相关产品推荐
相关产品推荐

