4

私は TDD の初心者で、NUnit を使用して C# でカード ゲーム アプリケーションのテストを記述しています。

ほとんどの場合、非常に有用であることが証明されていますが、テストしたいことがいくつかありますが、そのためのパブリック プロパティを公開したくありません。

たとえば、新しいカード デッキが、それぞれ 13 枚のカードを含む 4 つのスートで構成されていることをテストできるようにしたいと考えています。次のようになります。

[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 を公開したくない場合もあります) が、それらを公開せずにテストする方法がわかりません。

これを行う一般的に受け入れられている方法はありますか?

乾杯

スチュワート

4

5 に答える 5

1

このシナリオでは、(悪用?) フレンド アセンブリを使用して、テスト プロジェクトがテスト対象のクラスの内部メンバーを参照できるようにします。

編集:

メイン プロジェクトに FriendAssemblies.cs ファイルを追加します。

using System.Runtime.CompilerServices;

// making internals available to the testing project
[assembly: InternalsVisibleTo( "MyProject.IntegrationTests" )]
[assembly: InternalsVisibleTo( "MyProject.UnitTests" )]
于 2012-05-07T23:45:58.153 に答える
0

クラスの公開動作をテストする必要があります。UI が に話しかけ、Gameスーツの数を知る必要がある場合は、複数の Deck があるかどうかをgame.Deck.SuitCountテストするのではなくgame.GetDeckSuitCount()、パラメータを介してどの Deck を指定するかをメソッドにオーバーロードしますgame.GetDeckSuitCount(2)。この方法Deckは のクライアントから隠され、Gameカプセル化されています。

Deckまた、テストとそれが提供するサービスを個別にテストする必要があるかもしれないことも考慮してください。その場合、のコンストラクターGameを介して明示的に Game への依存関係として提供することが望ましいでしょう。Game

このアプローチでは、実装ではなくインターフェイスに依存することもできます。これにより、モック用に別の実装を提供Deckしたり、将来的に別の実装を柔軟に提供できるようになります。GameDeckGame

例えば

public interface IDeck{
    // provide the methods and properties that Game requires from Deck
}

public class PokerDeck:IDeck{
    // ... etc
}

public class TravelCardsDeck:IDeck{
    // ... etc
}

// [Test]
IDeck deck = new TravelCardsDeck();
var game = new Game(deck);
Assert.That(game.GetDeckSuitCount(),Is.EqualTo(4));
于 2012-05-07T15:58:50.710 に答える
0

この場合、私はすぐに内容を気にしません。アクトをモデル化すると、デッキになるカードのセットが与えられます (以下では、aDeckは を受け取りますIEnumerable<Card>)。次に、それらをシャッフルして配ります。

public class Deck
{
    ...
    public Deck(IEnumerable<Card> cards) { ... Shuffle() ... }        
    public void DealTo(IDealable dealable, int numberOfCards) {...}
}

ここでは、1 枚のカードを配る簡単なテスト ケースを作成します。

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);
于 2012-05-07T22:28:27.823 に答える
0

示唆されているように、InternalsVisibleTo属性を使用して、テスト アセンブリが製品アセンブリのコードを実行できるようにします。

ただし、内部の動作と実装を個別の内部クラスに抽出します。

このようにして、内部動作に依存せずにパブリック API クラスをテストできます。内部動作が変更された場合、動作のテストのみが影響を受けます。そうしないと、脆弱なテストや、内部実装の変更により壊れる可能性のあるパブリック API テストが発生します。

于 2012-05-08T05:52:17.400 に答える