JUnit测试StudentGradeGenerator错误信息断言异常问题咨询
问题描述
我正在用JUnit测试ProgramFunctions包下StudentGradeGenerator类的ValidateMark方法,该方法会在输入不合法时设置对应错误信息。测试时验证错误信息是否正确,但对比预期错误信息数组时出现断言失败:当测试输入为"0"(对应索引2)时,断言提示预期值为"Line (0): Final Mark must be a value between 0 and 60!",但实际获取的错误信息为空字符串——尽管预期数组FinalMarkExpectedErrorSet的索引2位置是空字符串,我怀疑数组未被正确遍历。
测试类代码
package ProjectUnitTest; import static org.junit.jupiter.api.Assertions.*; import java.net.URL; import ProgramFunctions.StudentGradeGenerator; import org.junit.jupiter.api.Test; class StudentGradeGeneratorTest { @Test void TestFinalMark() { int expectedIndex = 0; String[] MarkInputs = new String[] { "d20", "-10", "0", "55", "60", "70" }; int[] exepected = new int[] { -1, -1, 0, 55, 60, -1 }; String[] FinalMarkExpectedErrorSet =new String[]{ "Line (0): Final Mark must be of type int!", "Line (0): Final Mark must be a value between 0 and 60!", "", "", "", "Line (0): Final Mark must be a value between 0 and 60!" }; for (var mark : MarkInputs) { int actual = StudentGradeGenerator.ValidateMark("Final Mark", mark, 60); assertEquals(exepected[expectedIndex], actual,String.format("mark::%s => Returning Error in validating Final Mark Function",mark)); assertEquals(StudentGradeGenerator.getError(),FinalMarkExpectedErrorSet[expectedIndex],String.format("mark::%s,index::%d =>Error in::Error set in Final Mark Function",mark,expectedIndex)); expectedIndex++; } }
被测试类代码
package ProgramFunctions; import java.io.BufferedReader; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.lang.String; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Iterator; import java.util.Vector; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; public class StudentGradeGenerator { /*the error variable is used to store the error *raised by any function. which is used later to in the gui *to display it to the user. */ private static String _error=""; /*the ErrorlineNumber is used to display the * line of the error. * it's first initalized to zero, then in the * InputParse function the variable is increased for every * line being parsed by one. */ private static int ErrorlineNumber=0; /*function to validate if the mark is: * 1) of type int. * 2) value between 0 and a maximum mark. */ public static int ValidateMark(String MarkName,String mark,int MaxMark) { try { /*parse the string number in case of : * success: this means that mark is of type int * (then the value will be checked if it's between 0 & MaxMark). * fail: an exception will occur. */ int Mark =Integer.parseInt(mark); /*check if the mark between 0 & MaxMark: * if it's : the value is correct and will be returned. * else: an error will be raised and the function will return with value -1. */ if(Mark>=0 && Mark<=MaxMark) return Mark; _error ="Line ("+ErrorlineNumber+"): "+MarkName +" must be a value between 0 and "+ MaxMark +"!"; return -1; } catch(Exception e) { /*if we reached here then that's means the mark wasn't of type int. * first raise an error then return with value -1. */ _error ="Line ("+ErrorlineNumber+"): "+MarkName+" must be of type int!"; return -1; } } public static String getError(){ return _error; } }
错误输出
AssertionFailedError: mark::0,index::٢ =>Error in::Error set in Final Mark Function ==> expected: <Line (0): Final Mark must be a value between 0 and 60!> but was: <>
问题分析与解决方案
核心问题
assertEquals参数顺序颠倒:JUnit的
assertEquals方法要求预期值在前,实际值在后,当前代码把实际错误信息(StudentGradeGenerator.getError())放在第一个参数,预期值(FinalMarkExpectedErrorSet[expectedIndex])放在第二个,导致断言逻辑错误,且错误提示的预期/实际值完全搞反。静态_error变量未重置:
ValidateMark方法在输入合法时直接返回结果,没有清空静态变量_error的内容,导致当前测试用例的错误信息残留了上一次测试的结果(比如输入"0"时,_error还是上一次输入"-10"设置的错误字符串)。
修复步骤
1. 修正assertEquals参数顺序
将错误信息断言的参数顺序调整为预期值在前,实际值在后:
assertEquals(FinalMarkExpectedErrorSet[expectedIndex], StudentGradeGenerator.getError(), String.format("mark::%s,index::%d =>Error in::Error set in Final Mark Function", mark, expectedIndex));
2. 重置静态_error变量
修改ValidateMark方法,在每次调用时先清空错误信息,避免残留:
public static int ValidateMark(String MarkName,String mark,int MaxMark) { _error = ""; // 每次调用先清空错误信息 try { int Mark = Integer.parseInt(mark); if(Mark>=0 && Mark<=MaxMark) return Mark; _error ="Line ("+ErrorlineNumber+"): "+MarkName +" must be a value between 0 and "+ MaxMark +"!"; return -1; } catch(Exception e) { _error ="Line ("+ErrorlineNumber+"): "+MarkName+" must be of type int!"; return -1; } }
额外优化建议
静态变量_error和ErrorlineNumber会导致测试用例之间的状态干扰(比如连续测试时,上一次的错误信息会影响下一次),建议将这些变量改为实例变量,通过创建StudentGradeGenerator实例来调用方法,而非使用静态方法,提升代码的可测试性和线程安全性。
内容的提问来源于stack exchange,提问作者Alaa

