我正在学习JUnit测试程序,并且已经完成了我能找到的所有教程。我理解实现基本测试的概念,例如当一个方法需要一些输入并使用它们来计算返回值时。在这种情况下,编写一个断言预期返回值应该是什么的测试很简单。
但是,当有更复杂的测试方法时,如果使用从Random对象生成的数字,或者如果需要测试不返回值的方法,那会怎样做?
例如,我有以下方法可以编写测试:
// 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.");
}
}
我将如何为此编写正式测试?由于代码中有三个谓词语句,我知道代码中应该有三条不同的路径:
火鱼雷&gt;点击(否)&gt;端
火鱼雷&gt;点击(是)&gt;计算损害&gt;被毁坏(不)&gt;容器保持&gt;端
火鱼雷&gt;点击(是)&gt;计算损害&gt;被毁坏(是)&gt;船离开&gt;端
因此,如果我想获得完整的路径覆盖,我需要编写至少三个表达这些条件的测试用例。很容易看出这些价值观是什么。但是我如何使用它们来编写测试?例如,JUnit可以访问我的代码中的布尔命中值,以便我可以在不使用随机数的情况下定义值吗?我知道我可以通过代码来查看它是否正常工作(我有),但我被告知我应该使用更正式的测试手段,比如JUnit。
我希望这些问题有意义。我只是希望更好地了解在现实世界中如何进行这种测试。
答案 0 :(得分:3)
然而,当有更复杂的测试方法时,人们会怎么做,例如可能使用从Random对象生成的数字的方法
您找到了控制Random
的方法。例如,您可以将其传递给方法,并且具有无参数的重载,如果您确实需要,则使用new Random()
调用它。
通过这种方式,您的测试可以传入他们想要的任何Random
实例 - 例如一个具有预设种子,或者一个使用模拟框架来允许您控制返回的值。
或者是否需要测试不返回值的方法?
你测试副作用。你的方法必须有副作用,否则就没有意义了。您只需要一种访问这些副作用的方法(例如,通过调用target.getHitPoints()
。
现在你的方法似乎有“模型”副作用和 UI副作用......而且它也很长。这两个都会让人难以测试。将代码拆分为更小,更集中的方法通常可以更轻松地阅读和更容易测试。在这方面,将UI与业务逻辑分开也有帮助。