【问题标题】:Junit testing void against class type Java [closed]针对类类型 Java 的 Junit 测试 void [关闭]
【发布时间】:2016-01-03 00:21:15
【问题描述】:

我在测试 void 函数时遇到问题。

如果您查看下面的代码,那么当我希望对此进行测试时,我最终会得到一个 (Deck, void) 并且无法对其进行测试(请参阅 DeckTest)

编辑:如何测试是否已创建一副纸牌,即public void createDeck()

public class Deck {

public Deck() {
    this.cards = new ArrayList<Card>();
}

...

public void createDeck() {
    for (Suit suit : Suit.values()) {
        for (Rank rank : Rank.values()) {
            this.cards.add(new Card(rank, suit));
        }
    }
}

...

}

现在进行junit测试

public class DeckTest extends TestCase {

Deck deck = new Deck();

@Test
public void testCreateDeck() throws Exception {
    assertEquals(deck, deck.createDeck()); <--- I have (Deck, void)
}

...

}

如何在 Junit 中使用我的“public void createDeck”来测试是否已创建卡组?

查看完整代码的链接

https://gist.github.com/kazyka/7a56617337d21706ec5e

【问题讨论】:

  • 代码,你面临的问题,以及解决它的尝试,必须在问题中。
  • 试着用文字表达你想要用你的测试断言什么(什么条件、行为、合同)。
  • 由于您的方法影响cards 变量而不返回任何内容,您应该使用cards 进行断言,例如断言您希望它包含哪些特定卡片。
  • 所以你想让我把public void createDeck()改成public Card createDeck()?但我在这里不需要返回任何东西,我只希望创建一副牌

标签: java testing junit void


【解决方案1】:

想想你想测试哪些方面。

你要测试吗...

  • ...如果有 52 张卡片进入您的列表?
  • ...如果您的清单中有四种不同的套装?
  • ...如果您的列表中有 13 张数字和面部卡片?

理想情况下,您应该测试所有三个方面,但真正的问题在于方法的编写方式。你不能孤立地测试这些东西之一。

请注意,这个函数是void 实际上并不重要void 方法只是意味着你的对象的状态已经改变,要测试它,你需要测试状态。但是,我马上就会讲到。

首先,我们需要对您的逻辑进行一些重组。

让我们首先编写一个方法,允许我们为给定的花色生成所有 13 张牌。这应该很简单。

密切注意此方法的可见性。这是我们想要公开以进行测试的方法,但不是天生开放供世界使用的方法。因此,我们使用包私有可见性。如果您有 Guava,请考虑使用 @VisibleForTesting 作为友好提醒,以提醒您为什么不是 publicprivate

List<Card> generateCardsForSuit(final Suit suit) {
    final List<Card> result = new ArrayList<>();
    for(Rank rank : Rank.values()) {
        result.add(new Card(rank, suit);
    }
    return result;
}

这可以单独测试。给定一个有效的Suit,它应该能够:

  • 生成 13 张卡片
  • 包含所有 13 个等级
  • 有一套连续的西装

有趣的是,我们已经测试了我们在这个特定功能中关心的 3 件事中的 2 件事。现在,让我们把它放回void 方法中。

public void createDeck() {
    for (Suit suit : Suit.values()) {
        this.cards.addAll(generateCardsForSuit(suit));
    }
}

我们将不得不公开一个 getter 来检索 cards 列表,这样我们就可以根据它的实例来实际验证事情。再次注意该方法的可见性。

List<Card> getCards() {
    return cards;
}

由于我们已经轻松地测试了给定花色中的牌张数量,测试了它们的一致性,并测试了它们的等级是否正确,所以我们需要做的就是测试我们是否因此生成了正确的数字方法,使用getCards() 作为窥探对象状态的一种方式。

这也让我们可以加入小丑,这将在牌组中引入 54 张牌,而不是只有 52 张牌,这将是一个独立于为牌组创建所有等级和花色的功能。

【讨论】:

    【解决方案2】:

    为了方便测试,您可以考虑按照以下方式重新设计:

    • Deck 类,以及
    • DeckFactory

    如果您这样做,您将能够测试DeckFactory 确实可以构造有效的Deck 实例。随着该类的测试,您可以在任何需要新的Deck 的地方使用它。

    这里有一些粗略的样板,可以让您了解我所说的要点:

    public class Cards {
    
        public static void main(String[] args) {
            final Deck deck = new DeckFactory().newInstance();
    
            //... do stuff with the deck...
        }
    }
    
    class Deck {}
    
    class DeckFactory {
        public Deck newInstance() {
            return new Deck();
        }
    }
    
    class DeckFactoryTest {
        private DeckFactory deckFactory;
    
        @Before
        public void setUp() {
            deckFactory = new DeckFactory();
        }
    
        @Test
        public void has52Cards() {
            //...
        }
    
        @Test
        public void has13Spades() {
            //...
        }
    }
    

    【讨论】:

    • 一个新的类是相当过分的......
    • @Makoto - 这可能是你的意见......就像我主张反对分离关注点是一种不明智的做法一样。为了促进富有成效的讨论,您对提供原始海报有什么实际建议吗?
    • 我已经发布了我的答案。就我个人而言,我并不反对关注点分离,但另一个类来做这件事似乎不是最干净的方法。
    • @Makoto - 一般来说,我不会混合模型和“交互者”类型的行为。您的解决方案与我的唯一不同之处在于,您没有使用创建 Deck 实例的工厂类,而是将所有逻辑捆绑到 Deck 类本身中(使用额外的方法来计算完整的套装)。你怎么觉得这更干净?
    【解决方案3】:

    assertEquals (deck, deck.createDeck()) 行将 Deck 对象与 void(由 createDeck() 方法返回)进行比较,因此断言将失败。

    【讨论】:

    • 如何在不将我的public void createDeck() 更改为public Card createDeck() 的情况下检查是否已创建“一副牌”
    猜你喜欢
    • 1970-01-01
    • 2012-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多