2016-12-07 60 views
-1

試圖學習如何在Java中進行測試,並認爲我現在已經很久了,因爲感覺就像我的試驗和錯誤越多,我越理解。我無法弄清楚如何通過填充模擬卡來測試甲板?我希望能夠在甲板上洗牌之前測試第一張牌中的第一張牌是真正的兩張牌,或者可以比較一下爲測試製作的全部牌,但現在它完全靜止不動。任何人有任何提示,以良好的方式測試甲板卡?測試一副撲克牌


Card.java

package model; 

public class Card { 

    public enum Value { 
     Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Knight, Queen, King, Ace 
    } 

    public enum Suite { 
     Hearts, Spades, Diamonds, Clubs 
    } 

    private Value value; 
    private Suite suite; 

    public Card(Value value, Suite suite) { 
     if(value == null || suite == null){ 
      throw new IllegalArgumentException("Argument can't be null"); 
     } 

     this.value = value; 
     this.suite = suite; 
    } 

    public Object getValue() { 
     return this.value; 
    } 

    public Object getSuite() { 
     return this.suite; 
    } 

    public String toString(){ 
     return value + " of " + suite; 
    } 
} 


Deck.java

package model; 
import java.util.ArrayList; 

public class Deck { 

    private ArrayList<Card> cards = new ArrayList<Card>(); 
    private CardFactory CF = new CardFactory(); 

    public Deck(){ 
     init(); 
    } 

    public void init() {   
     for (int i=0; i<13; i++){  
      for (int j=0; j<4; j++){ 
       //card = cardFactory.createCard(Card.Value.values()[i], Card.Suite.values()[j]); 
       this.cards.add(CF.createCard(Card.Value.values()[i], Card.Suite.values()[j]));   
      } 
     } 
    } 

    public Card getCard() {  
     return cards.remove(0); 
    } 

    public int cardsLeft() {   
     return cards.size();   
    } 

    public Card getLastCard() { 
     return cards.remove(cards.size()-1); 
    } 
} 


CardFactory.java

package model; 

public class CardFactory { 

    public Card createCard(Card.Value value, Card.Suite suite){ 
     return new Card(value, suite); 
    } 

} 


DeckTest.java

package model; 

import static org.mockito.Mockito.verify; 
import static org.mockito.MockitoAnnotations.initMocks; 

import java.util.ArrayList; 

import org.junit.Before; 
import org.junit.Test; 
import org.mockito.InjectMocks; 
import org.mockito.Mock; 
import org.mockito.Mockito; 

public class DeckTest { 

    @Mock private ArrayList<Card> cards; 
    @Mock private Card card; 
    @Mock private CardFactory CF; 

    @InjectMocks private Deck sut; 

    @Before 
    public void setUp() throws Exception { 
     initMocks(this); 
    } 

    @Test 
    public void DeckContains52Cards() {      
     sut.init();  
     verify(cards, Mockito.times(52)).add(Mockito.any()); 
    } 

    @Test 
    public void getCardIsCalled() {  
     sut.getCard(); 
     verify(cards).remove(0);   
    } 

    @Test 
    public void cardsLeftIsCalled() {  
     sut.cardsLeft();   
     verify(cards).size();  
    } 

    @Test 
    public void getLastCardIsCalled() {  
     sut.getLastCard(); 
     verify(cards).size();  
    } 
} 
+0

'CardFactory'根本無法自由定義要創建哪些卡。這不是工廠的工作方式。 理想情況下,您將創建一個抽象或接口'CardFactory',並且將注入一個具體的實現'PokerDeckCardFactory',它將一次生成所有卡片。您可以通過將其作爲參數傳遞給構造函數來注入CardFactory。 – SJuan76

+0

好吧,工廠主要是爲了能夠嘲笑工廠並返回嘲笑的卡片而不是使用「真正的」卡片(我沒有按照我的想法工作),將新卡片的創建從卡組中移出, 。但我會看看工廠,並返回一個完整的套牌。謝謝 –

回答

0

你得到它錯了。

首先你分離依賴關係。該CardFactory需要自由地生產它需要的牌:

public interface (or abstract class) CardFactory { 
    public List<Card> getCards(); 
} 

public class PokerCardFactory implements CardFactory { 
    public List<Card> getCards() { 
    ArrayList<Card> result = new ArrayList<>(); 
    for (int i=0; i<13; i++){  
     for (int j=0; j<4; j++){ 
     result.add(this.createCard(Card.Value.values()[i], Card.Suite.values()[j]));   
     } 
    } 
    return result; 
    } 

    private Card createCard(Value value, Suite suite) { 
    ... 
    } 
} 

那麼你注入的依賴關係(例如在構造函數),並用它來生成卡。

你想測試Deck而不是PokerCardFactory,所以你注入一個簡單的CardFactory來簡化測試。 mockito,讓你創建這樣一個工廠寫作方式少代碼。

@Mock private CardFactory cardFactory 
@Test 
public void numberOfCards { 
    ArrayList<Card> cards = new ArrayList(); 
    cards.add(new Card(Value.Two, Suite.Hearts)); 
    cards.add(new Card(Value.Three, Suite.Aces)); 
    when(cardFactory.getCards()).thenReturn(cards); // Now we have a CardFactory that will produce a deck with just two cards. 
    Deck deck = new Deck(cardFactory); // Dependency injection. 
    assertEquals("The number of cards does not match", 2, deck.getNumberOfCards()); // You have tested `getNumberOfCards`. 
} 
+0

我附近沒有任何mockito示例,所以可能會出現一些語法錯誤,但這是主意。 – SJuan76

+0

這種方式不是DeckTest依賴卡類嗎?例如,如果我打破卡類,不能這也打破DeckTest?我可以通過嘲笑牌來解決嗎?我順便謝謝你! –

0

好吧,如果你想測試,你的甲板上的第一張牌是二的心,你的測試應該是這個樣子:

Deck deck = new Deck(); 

Card firstCard = deck.getCard(); 

assertCard(firstCard, Value.Two, Suite.Hearts) // orwhatever 

沒有需求嘲笑呢,呵呵? ;)

但這基本上是錯誤的,因爲首先,第二張卡片可能是空間的王牌,第二,你不想測試'getCard',你想驗證,甲板電話CardFactory按正確順序排列。無論如何你已經使用過驗證,所以不需要解釋。 但我不喜歡這個測試,因爲我本身沒有看到任何價值。只要洗牌工作,它是52張卡片,沒有重複卡片,這個測試已經過時了,但我猜,這對於學習目的來說仍然有好處。

因爲我不能評論,@ SJuan76的回答:這個測試不測試任何東西。我可以切換卡片,我可以刪除第一個條目並將第二個條目添加到它的位置,或者我甚至可以將兩個null添加到新創建的列表中,並且測試仍然通過。它在重構之後唯一應該測試的就是驗證,因爲這是唯一的事情,並且從測試的角度來看,cardFactory.getCards被調用。

+0

感謝您的意見和建議,關於在甲板上測試什麼。做我自己的測試,而不僅僅是測試老師讓我測試的東西,這真是令人沮喪的幾天;) –

+0

嗯......測試驅動的開發工作是這樣的:寫入失敗的測試,實現(使其通過),重構(見Kent Beck或Freeman/Pryce的書)。 – slowy

+0

(我討厭它,那進入提交評論)。例如,getCard就是一個很好的例子。 _提供一張卡牌清單,當我打電話給卡片時_then_我希望卡牌的第一張牌被移除並返回,並且卡牌的數量少一個。 (提示:總是在給定時間模式下編寫測試,也可以像這樣進行格式化,它可以提高測試的可讀性並使其意圖更清晰) – slowy