如何用JUnit 5编写测试用例验证单词计数程序的统计结果?
解决方案:重构代码+JUnit 5测试实现
首先你的代码所有逻辑都耦合在main方法里,依赖硬编码的文件路径,还直接修改原文件,这种结构完全无法做单元测试。必须先重构代码,把核心的单词统计逻辑和IO操作分离,才能高效编写测试用例。
第一步:重构原代码
把统计、排序、写入操作拆分成独立方法,用Map替代两个ArrayList(更高效且符合语义):
import java.io.IOException; import java.io.InputStream; import java.util.*; import java.util.stream.Collectors; public class WordPopulation { // 修正类名大小写规范 // 核心统计逻辑:接收输入流,返回单词-计数映射 public static Map<String, Integer> countWords(InputStream inputStream) { Scanner scanner = new Scanner(inputStream); Map<String, Integer> wordCounts = new HashMap<>(); while (scanner.hasNext()) { String word = scanner.next(); wordCounts.put(word, wordCounts.getOrDefault(word, 0) + 1); } scanner.close(); return wordCounts; } // 按计数降序排序统计结果 public static List<Map.Entry<String, Integer>> sortByCountDesc(Map<String, Integer> wordCounts) { return wordCounts.entrySet() .stream() .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())) .collect(Collectors.toList()); } // 写入结果到文件 public static void writeResults(String filePath, List<Map.Entry<String, Integer>> sortedResults) throws IOException { try (var fw = new java.io.FileWriter(filePath, true); var bw = new java.io.BufferedWriter(fw); var out = new java.io.PrintWriter(bw)) { for (var entry : sortedResults) { out.println(); out.printf("%s occurred %d times%n", entry.getKey(), entry.getValue()); } } } public static void main(String[] args) throws IOException { try (InputStream inputStream = new java.io.FileInputStream("theraven.txt")) { Map<String, Integer> counts = countWords(inputStream); List<Map.Entry<String, Integer>> sorted = sortByCountDesc(counts); writeResults("theraven.txt", sorted); } } }
第二步:编写JUnit 5测试用例
通过ByteArrayInputStream模拟输入,避免依赖真实文件,覆盖各种测试场景:
import org.junit.jupiter.api.Test; import java.io.ByteArrayInputStream; import java.util.Map; import static org.junit.jupiter.api.Assertions.*; class WordPopulationTest { @Test void countWords_emptyInput_returnsEmptyMap() { String input = ""; try (var stream = new ByteArrayInputStream(input.getBytes())) { Map<String, Integer> result = WordPopulation.countWords(stream); assertTrue(result.isEmpty()); } } @Test void countWords_singleWord_returnsCountOne() { String input = "hello"; try (var stream = new ByteArrayInputStream(input.getBytes())) { Map<String, Integer> result = WordPopulation.countWords(stream); assertEquals(1, result.size()); assertEquals(1, result.get("hello")); } } @Test void countWords_repeatedWords_returnsCorrectCounts() { String input = "hello hello world hello"; try (var stream = new ByteArrayInputStream(input.getBytes())) { Map<String, Integer> result = WordPopulation.countWords(stream); assertEquals(2, result.size()); assertEquals(3, result.get("hello")); assertEquals(1, result.get("world")); } } @Test void countWords_mixedCaseWords_treatsAsDifferent() { // 原代码区分大小写,若需忽略可在统计时转成小写 String input = "Hello hello WORLD"; try (var stream = new ByteArrayInputStream(input.getBytes())) { Map<String, Integer> result = WordPopulation.countWords(stream); assertEquals(3, result.size()); assertEquals(1, result.get("Hello")); assertEquals(1, result.get("hello")); assertEquals(1, result.get("WORLD")); } } }
关键说明
- 解耦IO与业务逻辑:把统计逻辑从文件读取/写入中分离,测试时用内存流模拟输入,无需操作真实文件
- 场景覆盖:测试空输入、单单词、重复单词、大小写区分等典型场景,确保逻辑正确性
- 原代码优化点:原代码把排序放在循环内(每次循环都排序)是错误的,重构后改为排序一次再遍历
内容的提问来源于stack exchange,提问作者John Hendricks
相关产品推荐
相关产品推荐

