2014-05-22 54 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