如何用Mockito测试写法糟糕的void方法processData的过滤规则?
如何用Mockito测试这个耦合严重的
processData方法并验证过滤规则? 这个方法确实把DB操作硬编码得死死的,耦合性拉满,但咱们用Mockito还是能搞定测试的。核心思路就是mock掉所有DB的静态调用,同时构造针对性的测试数据来验证过滤逻辑。下面一步步来拆解:
1. 明确测试核心目标
我们要验证两件关键事情:
- DB操作的执行顺序完全符合预期:先连DB1、取原始数据,再连DB2、插入过滤后的数据
- 过滤规则生效:只有
passesFilter为true的对象才会被最终插入DB2
2. 准备测试依赖
确保你的测试依赖里包含:
- JUnit 5(或JUnit 4,根据项目情况选)
- Mockito核心包 + Mockito-inline包(因为要mock静态类,必须用inline扩展)
3. 编写测试的具体步骤
3.1 静态Mock DB类
因为DB的方法都是静态调用,所以得用Mockito.mockStatic来创建静态mock,这样我们才能完全控制它的返回值,后续也能验证调用行为。
3.2 构造测试用的原始数据
创建一批测试对象,故意包含符合过滤条件和不符合的实例,这样才能清晰验证过滤效果。比如假设你的数据对象是DataObject(换成你实际的类名就行):
DataObject validObj1 = new DataObject(); validObj1.passesFilter = true; DataObject validObj2 = new DataObject(); validObj2.passesFilter = true; DataObject invalidObj = new DataObject(); invalidObj.passesFilter = false; List<DataObject> rawData = Arrays.asList(validObj1, invalidObj, validObj2);
3.3 模拟DB的行为
让DB.getRawData()返回我们构造好的测试数据,至于connectToDB1、connectToDB2这类无返回值的方法,我们不需要模拟返回,只需要后续验证调用即可。
3.4 调用目标方法
实例化processData所在的类,直接调用这个void方法。
3.5 验证逻辑正确性
- 验证DB调用顺序:必须严格按照
connectToDB1()→getRawData()→connectToDB2()→insertProcessedData()的顺序执行 - 验证插入的数据:
insertProcessedData()的参数必须是只包含两个有效对象的列表
4. 完整测试代码示例
import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; import static org.mockito.Mockito.*; import java.util.Arrays; import java.util.List; class DataProcessorTest { // 替换成processData所在类的测试类名 @Test void processData_ShouldFilterInvalidObjectsAndFollowDBOrder() { // 1. 构造测试数据 DataObject validObj1 = new DataObject(); validObj1.passesFilter = true; DataObject validObj2 = new DataObject(); validObj2.passesFilter = true; DataObject invalidObj = new DataObject(); invalidObj.passesFilter = false; List<DataObject> rawData = Arrays.asList(validObj1, invalidObj, validObj2); List<DataObject> expectedProcessedData = Arrays.asList(validObj1, validObj2); // 2. 静态Mock DB类(try-with-resources自动关闭mock) try (MockedStatic<DB> mockedDB = mockStatic(DB.class)) { // 3. 模拟DB.getRawData返回测试数据 mockedDB.when(DB::getRawData).thenReturn(rawData); // 4. 调用目标方法 DataProcessor target = new DataProcessor(); // 替换成processData所在类的实例 target.processData(); // 5. 验证调用顺序和参数 InOrder inOrder = inOrder(mockedDB); inOrder.verify(DB::connectToDB1).times(1); inOrder.verify(DB::getRawData).times(1); inOrder.verify(DB::connectToDB2).times(1); inOrder.verify(DB::insertProcessedData).withArguments(expectedProcessedData).times(1); } } // 假设的DataObject类,根据实际业务替换 static class DataObject { boolean passesFilter; } }
5. 额外注意事项
- 如果
passesFilter是方法(比如obj.passesFilter())而不是属性,那你需要mock每个测试对象的这个方法,返回对应的布尔值:DataObject validObj1 = mock(DataObject.class); when(validObj1.passesFilter()).thenReturn(true); - 顺带提一句:这个方法的设计确实不够优雅,后续建议重构——把DB操作抽象成接口,通过依赖注入的方式传入类中,这样就不用搞静态mock了,测试会更简洁易维护。不过当前先把测试搞定再说~
内容的提问来源于stack exchange,提问作者Noob
相关产品推荐
相关产品推荐

