私はJavaEEの世界から来ましたが、現在は.Netプロジェクトに取り組んでいます。Javaでは、保護されたメソッドをテストしたいときは非常に簡単で、同じパッケージ名のテストクラスを用意するだけで十分でした。
C#に似たものはありますか?保護されたメソッドをユニットテストするための良い方法はありますか?パブリックメソッドのみをテストする必要があると言っているフレームワークと人々だけを見つけました。
フレームワークなしでそれを行うことが可能であるはずです…</p>
私はJavaEEの世界から来ましたが、現在は.Netプロジェクトに取り組んでいます。Javaでは、保護されたメソッドをテストしたいときは非常に簡単で、同じパッケージ名のテストクラスを用意するだけで十分でした。
C#に似たものはありますか?保護されたメソッドをユニットテストするための良い方法はありますか?パブリックメソッドのみをテストする必要があると言っているフレームワークと人々だけを見つけました。
フレームワークなしでそれを行うことが可能であるはずです…</p>
テストしているクラスをテストクラスで継承できます。
[TestClass]
public class Test1 : SomeClass
{
[TestMethod]
public void MyTest
{
Assert.AreEqual(1, ProtectedMethod());
}
}
もう1つのオプションはinternal
、これらのメソッドに使用InternalsVisibleTo
してから、を使用してテストアセンブリがこれらのメソッドにアクセスできるようにすることです。これは、同じアセンブリ内の他のクラスによって消費されるメソッドを停止しませんが、テストアセンブリではない他のアセンブルによるメソッドへのアクセスを停止します。
これは、カプセル化と保護をそれほど提供しませんが、非常に簡単で、便利な場合があります。
AssemblyInfo.cs
内部メソッドを含むアセンブリに追加する
[assembly: InternalsVisibleTo("TestsAssembly")]
テストするクラスを継承する新しいクラスで、保護されたメソッドを公開できます。
public class ExposedClassToTest : ClassToTest
{
public bool ExposedProtectedMethod(int parameter)
{
return base.ProtectedMethod(parameter);
}
}
PrivateObjectクラスを使用して、すべてのプライベート/保護されたメソッド/フィールドにアクセスできます。
PrivateObjectは、Microsoftユニットテストフレームワークのクラスであり、通常はアクセスできないメンバーをユニットテストに呼び出すことができるラッパーです。
リフレクションを使用して、プライベートメソッドと保護されたメソッドを呼び出すことができます。
詳細については、こちらをご覧ください。
受け入れられた答えは最良の答えですが、それは私の問題を解決しませんでした。保護されたクラスから派生すると、他の多くのもので私のテストクラスが汚染されました。最終的に、テスト対象のロジックをパブリッククラスに抽出し、それをテストすることにしました。確かに、これはすべての人に役立つわけではなく、かなりのリファクタリングが必要になる可能性がありますが、この答えまでスクロールすると、役立つ場合があります。:)これが例です
古い状況:
protected class ProtectedClass{
protected void ProtectedMethod(){
//logic you wanted to test but can't :(
}
}
新しい状況:
protected class ProtectedClass{
private INewPublicClass _newPublicClass;
public ProtectedClass(INewPublicClass newPublicClass) {
_newPublicClass = newPublicClass;
}
protected void ProtectedMethod(){
//the logic you wanted to test has been moved to another class
_newPublicClass.DoStuff();
}
}
public class NewPublicClass : INewPublicClass
{
public void DoStuff() {
//this logic can be tested!
}
}
public class NewPublicClassTest
{
NewPublicClass _target;
public void DoStuff_WithoutInput_ShouldSucceed() {
//Arrange test and call the method with the logic you want to test
_target.DoStuff();
}
}
基本クラスから保護されたメソッドを呼び出すパブリックメソッドを使用してスタブを作成できます。これは、本番環境でこの保護された方法を使用する方法でもあります。
public class FooStub : Bar
{
public string MyMethodFoo()
{
return MyMethodBar();
}
}
public abstract class Bar
{
protected string MyMethodBar()
{
return "Hello World!"
}
}
これが、テストプロジェクトで使用している拡張方法(拡張方法とは何ですか?)です。唯一の欠点は、保護ルールに従い、保護されたメンバーまたはプライベートメンバーを参照できないstring
ため、文字通り名前をaとして記述する必要があることです。nameof()
public static MethodInfo GetNonPublicMethod(this Type type, string method)
{
MemberInfo[] temp = type.GetMember(method, MemberTypes.Method, BindingFlags.NonPublic | BindingFlags.Instance);
if (temp.Length == 1)
{
if (temp[0] is MethodInfo ret)
{
return ret;
}
else
{
throw new ArgumentException("Not a method.");
}
}
else
{
if (temp.Length == 0)
{
throw new ArgumentException("Method was not found.");
}
else
{
throw new ArgumentException("Multiple methods found.");
}
}
}
この方法の詳細については、https ://docs.microsoft.com/en-us/dotnet/api/system.type.getmember?view=net-5.0をご覧ください。
PS:methodInfo.Invoke(instance, params)
それを呼び出すために使用します。