Java 为更复杂的方法编写JUnit测试
我正在学习JUnit测试程序,并且已经阅读了我能找到的所有教程。我理解实现基本测试的概念,例如当一个方法接受两个输入并使用它们来计算返回值时。在这种情况下,编写一个断言预期返回值应该是什么的测试很简单 然而,当有一个更复杂的方法需要测试时,比如使用随机对象生成的数字,或者如果需要测试一个不返回值的方法,该怎么办 例如,我想为以下方法编写一个测试:Java 为更复杂的方法编写JUnit测试,java,unit-testing,testing,junit,Java,Unit Testing,Testing,Junit,我正在学习JUnit测试程序,并且已经阅读了我能找到的所有教程。我理解实现基本测试的概念,例如当一个方法接受两个输入并使用它们来计算返回值时。在这种情况下,编写一个断言预期返回值应该是什么的测试很简单 然而,当有一个更复杂的方法需要测试时,比如使用随机对象生成的数字,或者如果需要测试一个不返回值的方法,该怎么办 例如,我想为以下方法编写一个测试: // Requirement 9.5.0 public void firePhotonTorpedos(TrekGUI gui, Starship t
// Requirement 9.5.0
public void firePhotonTorpedos(TrekGUI gui, Starship target, int score)
{
// Requirement 9.5.1.1
// Torpedoes can either hit or miss.
Random rand = new Random();
boolean hit = false;
int isItAHit= rand.nextInt(10);;
int damage = 0;
//80 % chance of hitting target
if(isItAHit < 8)
{
hit = true;
}
// if it was a hit, calculate damage
if(hit)
{
//damage between 30 and 50
damage = rand.nextInt(21) + 30;
target.setHitPoints(target.getHitPoints() - damage);
}
this.setPhotonTorpedos(this.getPhotonTorpedos() - 1);
// Requirement 5.4.1
this.setEnergy(this.getEnergy() - 50);
//if target hit but not destroyed, say so
if(hit && target.getHitPoints() > 0)
{
gui.getBottomPanel().getConsole().append("\nVessel at " + target.getQuadrantLocation() + ", " + target.getSectorLocation() + " damaged.");
gui.getBottomPanel().getConsole().append("\n" + damage + " units damage.");
}
//if target destroyed, say so and remove its ship
// Requirement 6.2.0
else if(hit && target.getHitPoints() < 0)
{
//warship is gone, so set its contains field to false and remove its icon
target.getSectorLocation().setContainsWarship(false);
target.getSectorLocation().getSectorView().hideWarshipIcon();
klingonsLeft = klingonsLeft - 1;
gui.getBottomPanel().getConsole().append("\n" + damage + " units damage.");
gui.getBottomPanel().getConsole().append("Vessel at " + target.getQuadrantLocation() + ", " + target.getSectorLocation() + " destroyed.");
// Increase score (bonus depending on how much energy is left)
int bonus = this.getEnergy()/20;
score = score + (50 + bonus);
}
//if it was a miss, say so
else
{
gui.getBottomPanel().getConsole().append("Torpedo missed.");
}
}
//要求9.5.0
公共虚空火箭筒(TrekguiGUI,星际飞船目标,智力分数)
{
//要求9.5.1.1
//鱼雷可能命中或未命中。
Random rand=新的Random();
布尔命中=假;
int-isItAHit=rand.nextInt(10);;
int损害=0;
//80%的命中率
如果(isItAHit<8)
{
命中=真;
}
//如果是命中,计算伤害
如果(命中)
{
//30到50之间的损坏
损坏=兰特·耐克斯汀(21)+30;
target.setHitPoints(target.getHitPoints()-伤害);
}
this.setPhotonTorpedos(this.getPhotonTorpedos()-1);
//要求5.4.1
this.setEnergy(this.getEnergy()-50);
//如果目标命中但未被摧毁,请说明
if(命中目标(&target.getHitPoints()>0)
{
gui.getBottomPanel().getConsole().append(“\n在“+target.getQuadrantLocation()+”,“+target.getSectorLocation()+”损坏“);
gui.getBottomPanel().getConsole().append(“\n”+伤害+”单位伤害“);
}
//如果目标被摧毁,说出来并移除它的飞船
//要求6.2.0
else if(命中目标(&target.getHitPoints()<0)
{
//战舰消失了,所以将其包含字段设置为false并移除其图标
target.getSectorLocation().setContainsWarship(false);
target.getSectorLocation().getSectorView().hideWarshipIcon();
klingonsLeft=klingonsLeft-1;
gui.getBottomPanel().getConsole().append(“\n”+伤害+”单位伤害“);
gui.getBottomPanel().getConsole().append(“容器位于“+target.getQuadrantLocation()+”,“+target.getSectorLocation()+”销毁”);
//增加分数(奖金取决于剩余能量的多少)
int bonus=this.getEnergy()/20;
分数=分数+(50+奖金);
}
//如果是失误,就说出来
其他的
{
gui.getBottomPanel().getConsole().append(“鱼雷丢失”);
}
}
我将如何为此编写正式测试?因为我在代码中有三条谓词语句,所以我知道我应该有三条通过代码的独立路径:
发射鱼雷>命中(否)>结束
发射鱼雷>命中(是)>计算伤害>摧毁(否)>船只残骸>结束
发射鱼雷>命中(是)>计算伤害>摧毁(是)>船只消失>结束
因此,如果我想获得完整的路径覆盖,例如,我需要编写至少三个测试用例来表达这些条件。很容易看出这些值可能是什么。但是我如何使用它们来编写测试呢?例如,JUnit是否可以访问代码中的布尔命中值,以便在不使用随机数的情况下定义该值?我知道我可以一步一步地检查代码是否正常工作(我已经这样做了),但有人告诉我应该使用更正式的测试手段,比如JUnit
我希望这些问题有意义。我只是希望能够更好地了解这种测试是如何在真实场景中进行的
然而,当有一种更复杂的方法需要测试时,比如使用随机对象生成的数字时,我们该怎么办
您可以找到一种控制随机性的方法。例如,您可以将其传递到方法中,并使用一个无参数重载,如果您确实想调用它,可以使用new Random()
调用它
这样,您的测试可以通过他们想要的任何随机实例-例如,一个带有预设种子的实例,或者一个使用模拟框架允许您控制返回值的实例
或者如果需要测试一个不返回值的方法
你测试一下副作用。你的方法肯定有副作用,否则就毫无意义了。您只需要一种访问这些副作用的方法(例如,通过调用target.getHitPoints()
)
现在,您的方法似乎有“模型”副作用和UI副作用……而且它也相当长。这两种副作用都会使测试变得困难。将代码拆分为更小、更集中的方法通常会使其更易于阅读和测试。在这方面,将UI与业务逻辑分离也会有所帮助
然而,当有一种更复杂的方法需要测试时,比如使用随机对象生成的数字时,我们该怎么办
您可以找到一种方法来控制该随机
。例如,您可以将其传递到该方法中,并使用一个无参数重载,如果确实需要,可以使用new Random()
调用它
这样,您的测试可以通过他们想要的任何随机实例-例如,一个带有预设种子的实例,或者一个使用模拟框架允许您控制返回值的实例
或者如果需要测试一个不返回值的方法
您可以测试副作用。您的方法必须有副作用,否则它毫无意义。您只需要一种访问这些副作用的方法(例如,通过调用target.getHitPoints()
)
现在,您的方法似乎有“模型”副作用和UI副作用……而且它也相当长。这两种副作用都会使测试变得困难。将代码拆分为更小、更集中的方法通常会使其更易于阅读和测试。将UI与业务逻辑分离有助于提高测试效率