LoginSignup
19
20

More than 1 year has passed since last update.

[C#]private、internalなメソッドのUnitTest

Last updated at Posted at 2019-06-27

もくじ

やりたいこと

作ったクラスやメソッドのUnitTestをしたいが、privateやinternalにしているメソッドはUnitTestプロジェクトのコードから見えないので、普通にはテストできなかった。どうにかしてテストしたい。

やり方

PrivateObjectやPrivateTypeクラスを使う。

private、internalメソッドを外から呼ぶ

PrivateObjectクラスのInvokeメソッドを使う。

  • テスト対象クラスをnewする
  • それを引数にして、PrivateObjectクラスをnewする
  • そのインスタンスで、PrivateObjectのInvokeメソッドを呼ぶ
  • Invokeの第一引数には対象のprivateのメソッド名を渡す
  • Invokeの第二引数以降にはそのメソッドに渡す引数を渡す
var cls1 = new Class1();
var pbObj = new PrivateObject(cls1);
ret = (string)pbObj.Invoke("AddPrivate", 1, 2);

private static、internal staticメソッドを外から呼ぶ

PrivateTypeクラスのInvokeStaticメソッドを使う。

  • テスト対象のクラスのtypeを引数にして、PrivateTypeをnewする
  • そのインスタンスで、PrivateTypeのInvokeStaticメソッドを呼ぶ
  • InvokeStaticの第一引数には対象のprivateのメソッド名を渡す
  • InvokeStaticの第二引数以降にはそのメソッドに渡す引数を渡す
PrivateType privateType = new PrivateType(typeof(Class1));
ret = (string)privateType.InvokeStatic("AddPrivateStatic", 1, 2);

子クラスから見た親クラスのprivateメソッドを外から呼ぶ

PrivateObjectクラスのInvokeメソッドを使う。
その際、PrivateObjectをnewするときの引数を変える。(詳細はサンプル参照)

  • テスト対象クラス(子クラス)をnewする
  • それを第一引数、第二引数に親クラスのtypeを引数にしたPrivateTypeをnewしたものを渡して、PrivateObjectクラスをnewする
  • そのインスタンスで、PrivateObjectのInvokeメソッドを呼ぶ
var clssub = new Class1Sub();
var pbObjSub = new PrivateObject(clssub, new PrivateType(typeof(Class1)));
ret = (string)pbObjSub.Invoke("AddPrivate", 1, 2);

サンプルコード

テストしたいdllを呼んで、UnitTestを行うためのプロジェクトのコード。

UnitTest1.cs
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ClassLibrary1;

namespace UnitTestProject1
{
    // 参考:https://www.gesource.jp/weblog/?p=7742

    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            var ret = "";
            var cls1 = new Class1();

            // publicなメソッドのテスト
            ret = cls1.AddPublic(1, 2);
            ret = Class1.AddPublicStatic(1, 2);

            // private、internalなメソッドのテスト
            var pbObj = new PrivateObject(cls1);
            ret = (string)pbObj.Invoke("AddPrivate", 1, 2);
            ret = (string)pbObj.Invoke("AddInternal", 1, 2);

            // private static、internal staticなメソッドのテスト
            PrivateType privateType = new PrivateType(typeof(Class1));
            ret = (string)privateType.InvokeStatic("AddPrivateStatic", 1, 2);
            ret = (string)privateType.InvokeStatic("AddInternalStatic", 1, 2);

            // 子クラスから見た親クラスのprivateメソッドをテスト
            var clssub = new Class1Sub();
            var pbObjSub = new PrivateObject(clssub, new PrivateType(typeof(Class1)));
            ret = (string)pbObjSub.Invoke("AddPrivate", 1, 2);
            ret = (string)pbObjSub.Invoke("AddInternal", 1, 2);

            // 子クラスから見た親クラスのprivate staticメソッドは、
            // 親クラスのprivate staticテストと同じ。
        }
    }
}

UnitTestから呼ぶ実験用dllのコード。
public、private、internalなメソッドと、その3つをstaticにしたメソッドを含む。

Class1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;

namespace ClassLibrary1
{
    public class Class1
    {
        public string AddPublic(int val1, int val2)
        {
            return MethodBase.GetCurrentMethod().Name + " " + (val1 + val2).ToString();
        }

        internal string AddInternal(int val1, int val2)
        {
            return MethodBase.GetCurrentMethod().Name + " " + (val1 + val2).ToString();
        }

        private string AddPrivate(int val1, int val2)
        {
            return MethodBase.GetCurrentMethod().Name + " " + (val1 + val2).ToString();
        }

        public static string AddPublicStatic(int val1, int val2)
        {
            return MethodBase.GetCurrentMethod().Name + " " + (val1 + val2).ToString();
        }

        internal static string AddInternalStatic(int val1, int val2)
        {
            return MethodBase.GetCurrentMethod().Name + " " + (val1 + val2).ToString();
        }

        private static string AddPrivateStatic(int val1, int val2)
        {
            return MethodBase.GetCurrentMethod().Name + " " + (val1 + val2).ToString();
        }
    }

    public class Class1Sub : Class1
    {

    }
}

コード

参考

MSTestでprivateメソッドをテストする
ほぼこちらを参考にさせていただいています。ありがとうございます。
https://www.gesource.jp/weblog/?p=7742

19
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
20