2014-05-22 51 views
0

我只是在学习JUnit测试程序,并已经通过了所有我可以找到的教程。我理解实现基本测试的概念,比如一个方法需要几个输入并使用它们来计算返回值。在这种情况下,编写一个测试来确定期望的返回值应该是什么,这很简单。为更复杂的方法编写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."); 
    } 
} 

我怎么会写这样一个正式的测试?由于我在码连续3条断言语句,我知道我应该通过代码有三个不同的路径:

火鱼雷>命中(无)>结束

火鱼雷>击(是)>计算损害>破坏(无)>船只仍然>结束

火鱼雷>击(是)>计算损害>破坏(是)>船不见了>结束

所以,如果我要得到完整的路径覆盖,例如,我需要编写至少三个表达这些条件的测试用例。很容易看出这些值可能是什么。但是,我如何使用它们来编写测试?例如,JUnit可以访问我的代码中的布尔命中值,以便我可以在不使用随机数的情况下定义值?我知道我可以通过代码来看看它是否工作(我有),但我被告知我应该使用更正式的测试手段,如JUnit。

我希望这些问题有意义。我只是希望更好地了解这种测试是如何在真实世界的场景中完成的。

回答

3

然而,当有测试更复杂的方法有哪些呢一个事情,比如也许一个使用从随机对象

生成的数字你会发现控制该Random的一种方式。例如,您可以将它传递给该方法,并且有一个无参数的超载,如果您真的想要,它会调用它,并使用new Random()

这样,您的测试可以通过他们想要的任何Random实例 - 例如,一个带有预设的种子,或者一个使用模拟框架来允许您控制返回的值。

或者如果需要测试一个不返回值的方法?

您测试了副作用。你的方法必须副作用,或者它是毫无意义的。你只需要的的方式访问那些副作用(例如,通过调用target.getHitPoints()

现在目前你的方法似乎有“模范”的副作用 UI副作用...它也很这些都会使测试变得困难。将代码分割成更小,更集中的方法通常使得易于阅读更易于测试。将UI与业务逻辑分开也有助于这方面的工作。

+0

谢谢,这很有帮助。你认为你可以给我示例一个新的Random()调用带无参数重载的方法吗?我不太了解那部分。 – Kallaste