如何为含Lambda表达式的myFunction编写单元测试验证全列表执行
验证
myFunction完整遍历列表的单元测试方案 原代码
public static void myFunction() { List<Integer> list = Arrays.asList(1,2,3,4,5,6); list.forEach(num -> { checkNumber(num); }); } public static void checkNumber(Integer num) throws RuntimeException { try { if(num.equals(3)) throw new RuntimeException("3 found not to execute"); System.out.println("mynum:"+num); } catch (Exception e) { System.out.println(e); } }
核心测试思路
要验证myFunction遍历完整列表,关键是记录每个元素的处理痕迹,确保所有元素(包括触发异常的3)都被checkNumber执行过。以下是两种可行方案:
方案1:重构代码提升可测试性(推荐)
原代码依赖控制台输出,不利于测试。通过抽象输出逻辑,解耦依赖后可以用Mock工具验证每个元素的处理情况:
- 定义输出接口
public interface OutputHandler { void printNumber(String message); void printException(Exception e); }
- 修改原类,注入输出逻辑
public class MyClass { private OutputHandler outputHandler; // 测试用构造方法 public MyClass(OutputHandler outputHandler) { this.outputHandler = outputHandler; } // 兼容原有调用的无参构造 public MyClass() { this.outputHandler = new ConsoleOutputHandler(); } public void myFunction() { List<Integer> list = Arrays.asList(1,2,3,4,5,6); list.forEach(this::checkNumber); } public void checkNumber(Integer num) throws RuntimeException { try { if(num.equals(3)) throw new RuntimeException("3 found not to execute"); outputHandler.printNumber("mynum:"+num); } catch (Exception e) { outputHandler.printException(e); } } // 默认控制台输出实现 private static class ConsoleOutputHandler implements OutputHandler { @Override public void printNumber(String message) { System.out.println(message); } @Override public void printException(Exception e) { System.out.println(e); } } }
- 编写JUnit+Mockito测试用例
import org.junit.jupiter.api.Test; import org.mockito.Mockito; import java.util.Arrays; import static org.mockito.Mockito.verify; public class MyClassTest { @Test void myFunction_processesAllNumbers() { OutputHandler mockHandler = Mockito.mock(OutputHandler.class); MyClass myClass = new MyClass(mockHandler); myClass.myFunction(); // 验证正常数字的输出调用 for (Integer num : Arrays.asList(1,2,4,5,6)) { verify(mockHandler).printNumber("mynum:" + num); } // 验证异常数字的异常处理调用 verify(mockHandler).printException(Mockito.argThat(e -> e instanceof RuntimeException && e.getMessage().equals("3 found not to execute") )); } }
方案2:不重构,拦截控制台输出(适合遗留代码)
如果无法修改原代码,可以通过拦截System.out收集输出,验证所有元素的处理痕迹:
import org.junit.jupiter.api.Test; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.Arrays; import java.util.List; import static org.junit.jupiter.api.Assertions.assertTrue; public class MyClassTest { @Test void myFunction_processesAllNumbers() { PrintStream originalOut = System.out; ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); try { MyClass.myFunction(); String output = baos.toString(); List<Integer> allNumbers = Arrays.asList(1,2,3,4,5,6); for (Integer num : allNumbers) { if (num == 3) { assertTrue(output.contains("3 found not to execute")); } else { assertTrue(output.contains("mynum:" + num)); } } } finally { System.setOut(originalOut); } } }
内容的提问来源于stack exchange,提问作者user404
相关产品推荐
相关产品推荐

