web-dev-qa-db-ja.com

パラメータ配列を使用したセットアップ方法

アプリケーションのテストを開発しています。パラメータとしてparams配列を持つメソッドがあります。 Moqを使用してメソッドを設定しましたが、テストを実行すると、メソッドの戻り値はnullです。つまり、モックされていません。

ここにコードサンプルがあります:

public interface ITicketManager {
    string GetFirstTicketInQueueIfMatches(params string[] ticketsToMatch);
}

public class TicketManager : ITicketManager {
    private Queue<string> ticketQueue = new Queue<string>();

    public string GetFirstTicketInQueueIfMatches(params string[] ticketsToMatch) {
        var firstQueuedTicket = ticketQueue.Peek();
        var firstQueuedTicketMatchesAnyOfRequested = ticketsToMatch.Any(t => t == firstQueuedTicket);

        if(firstQueuedTicketMatchesAnyOfRequested)
            return firstQueuedTicket;

        return null;
    }
}

モックコードは次のようになります。

var mock = new Mock<ITicketManager>();

mock.Setup(m => m.GetFirstTicketInQueueIfMatches(It.IsAny<string>()))
    .Returns(p => { 
    if(p.Contains("A"))
            return "A";

    return null;
});

なぜそれが偽のメソッドに当たらないのですか?

49
Luis Aguilar

配列ではなく単一の文字列を取るメソッドを呼び出そうとしています。 params部分を処理するのはC#コンパイラであり、個々の値を指定する呼び出しコードを配列で渡す呼び出しに変換することを覚えておいてください。メソッド自体に関する限り、それは単に配列を取得しているだけであり、それがあなたがモックしているものです。

コンパイラは実際にコードを次のように変換します。

mock.Setup(m => m.GetFirstTicketInQueueIfMatches
                        (new string[] { It.IsAny<string>() }))

それはあなたが望むものではありません。

あなたは使うべきです:

mock.Setup(m => m.GetFirstTicketInQueueIfMatches(It.IsAny<string[]>()))

単一の値のみが与えられることを確認する必要がある場合は、params以外のパラメーターの場合と同じ方法で行う必要があります。

基本的に、paramsはC#コンパイラにのみ影響を与えます-moqには影響しません。

74
Jon Skeet

_params string_はIt.IsAny<string[]>()ではなくIt.IsAny<string>()と一致する必要があると思います

12
Wiktor Zychla

以下のコードはMoqを使用して、params引数を持つメソッドにコールバックを設定します。 2番目の引数を配列として定義すると、うまくいきます。

        MockLogger
            .Setup(x => x.Info(It.IsAny<string>(), It.IsAny<object[]>()))
            .Callback<string, object[]>((x, y) => _length = x.Length);
0
Ben Wesson