我是TDD的新手,并且正在使用NUnit以C#书写卡片游戏应用程序的测试。
它的证明大多非常有用,但有一些我想测试的东西,但不希望公开任何公共属性。
例如,我希望能够测试一个新的卡片组由4个套装组成,每套套装有13张卡片。它可能看起来像:
[Test()]
public void ADeckOfCardsHas4Suits()
{
Game game = new Game();
Assert.AreEqual(4, game.Deck.SuitCount);
Assert.AreEqual(13, game.Deck.GetCards(Suit.Spades).Count)
}
使用SuitCount返回类似的内容:
return this.cards.Select(c => c.Suit).Distinct().Count();
和GetCards(西装):
return this.cards.where(c => c.Suit == suit);
但是我不想将API中的这些属性或方法暴露给UI(我甚至可能不希望暴露Deck),但我不确定如何在不公开它的情况下对它们进行测试。
有没有普遍接受的方法呢?
干杯
斯图尔特
答案 0 :(得分:1)
在这种情况下,我们经常使用(滥用?)朋友程序集来允许测试项目查看被测试类的内部成员。
编辑:
在您的主项目中添加一个FriendAssemblies.cs文件:
using System.Runtime.CompilerServices;
// making internals available to the testing project
[assembly: InternalsVisibleTo( "MyProject.IntegrationTests" )]
[assembly: InternalsVisibleTo( "MyProject.UnitTests" )]
答案 1 :(得分:0)
当然,你卡片组的客户应该能够访问并迭代给定桌面的卡片,不是吗?即套牌应该发布类似IEnumerable<Card>
的内容。
如果是这样,您的单元测试可以抓住它并使用它来计算不同套装的数量。因此,方法SuitCount
和GetCardsOfSuit
应该作为单元测试代码中的帮助程序实现。
答案 2 :(得分:0)
您应该测试班级的公共行为。如果UI与Game
对话,并且需要知道有多少套装,而不是game.Deck.SuitCount
测试game.GetDeckSuitCount()
如果你有超过1个Deck重载,那么通过a指定哪个Deck的方法参数game.GetDeckSuitCount(2)
。这种方式Deck
隐藏在Game
的客户端中并被封装。
还要考虑您可能需要独立测试Deck
及其为Game
提供的服务,在这种情况下,最好通过{{1}明确地将其作为依赖提供给Game。的构造函数。
此方法还允许您依赖于接口而不是实现,这有助于为模拟提供Game
到Deck
的不同实现,或者允许您将来可以灵活地为Game
提供Deck
的替代实施。
e.g。
Game
答案 3 :(得分:0)
在这种情况下,我不会立即关心内容。如果你对行为进行建模,你会获得一组成为牌组的牌(下面是Deck
取IEnumerable<Card>
)。然后你会把它们洗牌并解决它们。
public class Deck
{
...
public Deck(IEnumerable<Card> cards) { ... Shuffle() ... }
public void DealTo(IDealable dealable, int numberOfCards) {...}
}
在这里,您可以创建一个简单的测试用例来处理一张卡:
var deck = new Deck(new Card[] { <somecard> });
var hand = new Hand();
deck.DealTo(hand, 1);
Assert.AreEqual(<somecard>, hand[0]);
...加上你能想到的任何测试。
然后你创建一个扑克牌组:
public class PokerDeck : Deck
{
public PokerDeck() : base(<poker cards>)
}
// Pinochle, Uno, whatever
所以为了测试PokerDeck,你可能会从这样的事情开始:
var deck = new PokerDeck();
IDealable testHand = new TestDealable();
deck.DealTo(testHand, 52);
//assert all are distinct
//assert all make up expected deck
//assert is shuffled
// test with multiple players / "dealables"
模拟德州扑克会是这样的:
// first card
foreach(var player in players)
deck.DealTo(player, 1);
// second
foreach(var player in players)
deck.DealTo(player, 1);
// wait for action
// flop
deck.DealTo(burnPile, 1);
deck.DealTo(board, 3);
// wait for action
// turn
deck.DealTo(burnPile, 1);
deck.DealTo(board, 1);
// wait for action
// river
deck.DealTo(burnPile, 1);
deck.DealTo(board, 1);
答案 4 :(得分:0)
正如所建议的那样,我使用InternalsVisibleTo
attribut来允许测试程序集执行生产程序集的代码。
这样,我可以测试公共API类,而不依赖于任何内部行为,如果内部行为发生变化,只会影响行为测试;如果你不这样做,你会发现自己有一些脆弱的测试,以及由于内部实现变化而可能破坏的公共API测试。