我的任务是编写一个小程序以及JUnit和Coverage测试,我在理解如何编写JUnit时遇到了一些问题。
我之前已经编写了JUnit测试,在更多知识渊博的团队成员的帮助下,为其他课程项目提供了帮助。它们都是我们可以实例化,使用然后检查的类(使用assert...()
)。
我们被告知编写的程序是一个简单的控制台应用程序,它接受一些值,计算一些东西,然后返回。以下是我所写的内容,它只是在某个范围之间输入可变数量的数字,并计算值的最小值,最大值和平均值。
我遇到的问题是,我不知道如何根据我以前编写的方式编写JUnit。我不确定如何在单元测试中“伪造”用户输入到控制台。
我正在寻求帮助,我将如何为这个软件编写JUnit测试。
package softqa_assignment2;
import java.io.Console;
import java.util.LinkedList;
public class SoftQA_Assignment2
{
public static void main(String[] args)
{
Console cons = System.console();
if (cons == null)
{
System.err.println("System could not provide console, exiting");
System.exit(1);
}
System.out.println("--------------------");
System.out.println("Welcome, this program computes the minimum, maximum, and average of 10-20 numbers.");
System.out.println("Input \"Q\" at anytime to quit.");
System.out.println("--------------------");
int numVals = 0;
boolean gotNumVals = false;
while(!gotNumVals)
{
String numValsStr = cons.readLine("Enter number of numbers (10-20): ");
if(numValsStr.equals("Q"))
{
System.err.println("Encountered \"Q\", quiting program...");
System.exit(1);
}
try
{
numVals = Integer.parseInt(numValsStr);
}
catch(NumberFormatException e)
{
System.out.println("Please input a integer value between 10 and 20.");
continue;
}
if(numVals < 10 || numVals > 20)
{
System.out.println("Please input a integer value between 10 and 20.");
continue;
}
else
gotNumVals = true;
}
System.out.println("--------------------");
int valsGot = 0;
LinkedList<Double> vals = new LinkedList<>();
while(valsGot < numVals)
{
String numValueStr = cons.readLine((valsGot + 1) + ": Enter a number: ");
if(numValueStr.equals("Q"))
{
System.err.println("Encountered \"Q\", quiting program...");
System.exit(1);
}
double numToAdd = 0;
try
{
numToAdd = Double.parseDouble(numValueStr);
}
catch(NumberFormatException e)
{
System.out.println("Please input a proper value.");
continue;
}
vals.add(numToAdd);
valsGot++;
}
System.out.println("--------------------");
System.out.println("Done getting numbers, computing output...");
System.out.println("--------------------");
double min = Double.POSITIVE_INFINITY;
double max = Double.NEGATIVE_INFINITY;
double avg = 0.0;
for(int i = 0; i < vals.size(); i++)
{
avg += vals.get(i);
if(vals.get(i) < min)
min = vals.get(i);
if(vals.get(i) > max)
max = vals.get(i);
}
avg /= vals.size();
System.out.println("Minimum: " + min + "\n Maximum: " + max + "\n Average: " + avg);
System.out.println("--------------------");
}
}
答案 0 :(得分:2)
您的第一步是将您的代码refactor转换为小巧,可重复使用,有目的的方法。例如,在main
方法的末尾附近检查此代码块:
double min = Double.POSITIVE_INFINITY;
double max = Double.NEGATIVE_INFINITY;
double avg = 0.0;
for(int i = 0; i < vals.size(); i++)
{
avg += vals.get(i);
if(vals.get(i) < min)
min = vals.get(i);
if(vals.get(i) > max)
max = vals.get(i);
}
avg /= vals.size();
可以重构为:
Stats stats = getStatsFromVals(vals);
将新方法定义为:
static Stats getStatsFromVals(List<Double> vals) {
double min = Double.POSITIVE_INFINITY;
double max = Double.NEGATIVE_INFINITY;
double avg = 0.0;
for(double val : vals) {
avg += val;
if(val < min)
min = val;
if(val > max)
max = val;
}
avg /= vals.size();
return new Stats(min, max, avg);
}
Stats
将static nested class定义为{{3}},用作保存您正在计算的所有统计值的值类。
现在你有一个逻辑上和物理上都是单位的方法,使它成为单元测试的主要候选者。
@Test
public static void testGetStats() {
List<Double> testList = Arrays.asList("1.0, 2.0, 3.0");
Stats stats = MainClass.getStatsFromVals(testList);
assertEquals(1.0, stats.min);
assertEquals(3.0, stats.max);
assertEquals(2.0, Math.rint(stats.avg)); // risky FP math
}
正如评论中提到的,关键是让每个方法都将其参数作为输入,以便您可以将控制台输入与应用程序逻辑分开。
答案 1 :(得分:0)
你可以有一个布尔变量,让我们说条件=假。
现在如果程序能够正常运行而没有任何错误,那么在计算出你的最小值/最大值/平均值之后,你可以将它设置为true。然后用这个断言。在try和catch块之后,可以在finally块中进行此断言。如果出现任何错误,将调用catch并且不应将条件设置为true。因此断言应该返回否定。
如果您已经知道用户将输入的值,那么请使用适当的最小值/平均值进行断言。