2013-01-08 7 views
6

ユニットテストプロジェクトでプライベートメソッドをテストしようとしています。これまでは素晴らしかったですが、outパラメータを使ってメソッドをテストする必要があるときに、私はバンプを打ちました。そのメソッドのシグネチャは次のとおりです。PrivateObjectがパラメータを返さない

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

とunittestの(動作していない部分)は次のようになります。

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方法の仕事。私は単体テスト内でデバッグモードでテストしましたが、ssi out変数がtrueまたはfalseの値を返す前にメソッド内で設定されていることがわかります。しかし、テストがそれ自身のコードに戻ると、 'ssi'変数はまだヌルです。だから問題は、私が "GotSSI"メソッドで作成したオブジェクトは、PrivateObjectの呼び出しメソッドから解析されないということです。

誰かが私が迷っていることを知っていますか?

更新(ラファウによるソリューション)

ラファウのソリューションの仕事は完璧にして、ここで私は解決策を実装する方法です。

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

:(ターゲットは、私がテストしていたオブジェクトである)

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

そして私は、私がテストしたいオブジェクトを作成したとき、私は、デリゲートを構築:

は私がデリゲートを作成しました解決策は非常に簡単で、魔法のように動作

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

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

+0

はあなたのためにこれらを作るためのヘルパークラスを定義することは意味したりすることがあります:内部の静的T MakeDelegate (文字列methodNameの、Tのターゲット) {return(T)Delegate.CreateDelegate(typeof(T)、target、typeof(C).GetMethod(methodName、BindingFlags.NonPublic | BindingFlags.Instance));}しかし、おそらくあなたは既にそれを考えていました。 :-) – JLRishe

+0

本当に。この問題を抱えたのは1つのテストだけでしたが、私は時間がかかっていませんでした。良い考えではない。 – evilfish

答えて

3

アウト値を取得する場合は、outパラメータを使用したメソッドの呼び出しが間違っています。リフレクションで呼び出す方法については、thisを参照してください。

0

本当にプライベートメソッドをテストする必要がある場合は、自分に尋ねる必要がありますか?私は個人的に個人的な方法をテストしませんが、それはすべて個人的な意見になります(それはかなり熱くなります)。多くの理由/記事/意見があります。 A good SO thread can be found here

受け入れ答えからの抜粋である「プライベートメソッドは、クラスのユーザーに隠されるべき実装の詳細である。テストのプライベートメソッドブレークのカプセル化...

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

これは私の意見であり、多くの人が同意していないことを知っています。

+0

私は単体テストプライベートメソッドの一般的なコンセンサスを知っていますが、通常はそれをしません。ここでの問題は、私がテストしているこれらのメソッドは、私が使用できるpublicメソッドからセットアップするのが複雑であるということです。プライベートテストを使用すると、制御と理解がはるかに簡単になります。 – evilfish

+1

好奇心旺盛な人/理由がないのはなぜですか?あなたは投票を辞退する権利がありますが、理由を述べるのに役立ちます。そうでなければ、それはかなり無意味です。 – Belogix

4

受け入れられた最終的な解決策は機能しますが、それを行う方法はずっと簡単です。あなたが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; 
+0

私はそれを試して、適切に働いた。ありがとう。 – mggSoft

関連する問題