11

単体テスト プロジェクトでプライベート メソッドをテストしようとしています。これまでのところうまくいっていますが、out パラメーターを使用してメソッドをテストする必要があるときに問題が発生しました。そのメソッドのシグネチャは次のとおりです。

private bool GotSSI(out SSI ssi, RSI rsi)
{
        ~code omitted~
}

単体テスト (動作していない部分) は次のようになります。

SSI ssi = null;
object[] p = new object[]{ssi,rsi};
Type[] t = new Type[] { typeof(SSI).MakeByRefType(), typeof(RSI) };
actual = (bool) privateTarget.Invoke("GotSSI",t,p);

GotSSI メソッドが機能します。単体テスト内でデバッグ モードでテストしたところ、true または false の値を返す前に、'ssi' out 変数がメソッド内で設定されていることがわかります。しかし、テストが独自のコードに戻ったとき、「ssi」変数はまだ null です。問題は、「GotSSI」メソッドで作成したオブジェクトが、PrivateObject 呼び出しメソッドから解析されないことです。

誰が私が欠けているか知っていますか?

更新 (Rafal による解決策)

Rafalのソリューションは完全に機能し、ソリューションを実装した方法は次のとおりです。

デリゲートを作成しました:

delegate bool GotSSIInternal(out SSI ssi, RSI rsi);

そして、テストしたいオブジェクトを作成したら、デリゲートを作成します (ターゲットはテストしているオブジェクトです)。

GotSSIInternal gotSSIInternal = (GotSSIInternal) Delegate.CreateDelegate(
            typeof (GotSSIInternal), 
            target,
            typeof(OfflineResolver).GetMethod("GotSSI", BindingFlags.NonPublic | BindingFlags.Instance));

その後、デリゲートを呼び出すのは非常に簡単です。

actual = gotSSIInternal.Invoke(out ssi, rsi);

解決策は非常にシンプルで、魔法のように機能します。

4

4 に答える 4

10

受け入れられた最終的な解決策は機能しますが、もっと簡単な方法があります。Rafal からの受け入れられた回答で指定されたリンクをたどると、この質問と同様の質問が 2 つの回答で見つかります。2 番目の答え (最も「役立つ」点が多い) は、2 つのうちの単純なものです。

これは、特にテストシナリオ用のその回答の修正版です。

//method to test is a private method of the class ClassTotest with signature 
//    TryGetCustomerData(List<Invoice> invoices, out CustomerData customerData) 
//set up
var objToTest = new ClassToTest();
var invoices = GetInvoices();
CustomerData customerData = null;

//set up the arguments
var args = new object[] { invoices, customerData };
//get the MethodInfo of the method you want to test
var method = typeof(ClassToTest).GetMethod("TryGetCustomerData",
    BindingFlags.NonPublic | BindingFlags.Instance);
//invoke it
var success = (bool)method.Invoke(objToTest, args);
//get back the customerData argument - the "out" parameter
var actual = args[1] as CustomerData;
于 2013-06-13T15:53:27.180 に答える
3

out値を取得したい場合、outパラメーターを指定したメソッドの呼び出しは間違っています。リフレクションを使用して呼び出す方法については、こちらをご覧ください。

于 2013-01-08T11:12:04.733 に答える
0

プライベート メソッドを本当にテストする必要があるかどうかを自問する必要がありますか? 私は個人的に Private メソッドをテストしませんが、それはすべて個人的な意見によるものです (そしてかなり熱くなる可能性があります)。多数の理由/記事/意見があります。優れた SO スレッドはこちらにあります

受け入れられた回答からの抜粋は、「プライベートメソッドは、クラスのユーザーに隠されるべき実装の詳細です。プライベートメソッドをテストすると、カプセル化が破られます...

プライベート メソッドをテストしない理由は、パブリック インターフェイスよりも変更される可能性が高いためです。すべてのプライベート メソッドをカバーすると、リファクタリングがより複雑になります (これも私の意見です)。プライベート メソッドを変更してパブリック インターフェイスが壊れた場合、単体テストが失敗したことがわかり、ドリルダウンできます。

それは単なる私の意見であり、多くの人が反対していることを知っているので、そこに載せるだけです!

于 2013-01-08T11:16:17.793 に答える
0

PrivateObject技術的には「戻り値」ではありませんが、次のように使用できます。

object[] p = new object[] { null, rsi };
Type[] t = new Type[] { typeof(SSI).MakeByRefType(), typeof(RSI) };
actual = (bool)privateTarget.Invoke("GotSSI", t, p);
SSI ssi = p[0];

実際には、型配列なしでメソッドのオーバーロードを判断できる場合は、型配列を省略できます。

object[] p = new object[] { null, rsi };
actual = (bool)privateTarget.Invoke("GotSSI", p);
SSI ssi = p[0];
于 2021-03-09T05:08:33.113 に答える