.NET Core(C#): Moqのnew Mock<T>()とMock.Of<T>()の違い

はじめに

new Mock<T>()とMock.Of<T>()の違い

  • モック化対象オブジェクトを作成したいだけなら、Mock.Of<T>()の方が簡潔に使用できます。
    var target1Mock = new Mock<ITarget>();
    ITarget target1 = target1Mock.Object;
    
    ITarget target2 = Mock.Of<ITarget>();
  • プロパティやメソッドをモック化する際、new Mock<T>()は任意のタイミングで実装できますが、Mock.Of<T>()の場合は基本的に呼び出し時に実装します。多数のプロパティやメソッドをモック化する場合はnew Mock<T>()の方が便利です。
    Mock.Of<T>()に関して、引数で指定する不思議?なラムダ式はLINQを使った表現(LINQ to Mocks)です。Mock.Get()を使用して、後からモックオブジェクトの取得やSetup()を呼び出すこともできます。

    // new Mock<T>()によるプロパティ・メソッドのモック化
    var target1Mock = new Mock<ITarget>();
    target1Mock.Setup(o => o.StrProp).Returns("test");
    target1Mock.Setup(o => o.Add(2, 3)).Returns(5);
    ITarget target1 = target1Mock.Object;
    
    // Mock.Of<T>()によるプロパティ・メソッドのモック化(LINQ to Mocks)
    ITarget target2 = Mock.Of<ITarget>(o => 
        o.StrProp == "test" && o.Add(2, 3) == 5
    );
    
    // テスト
    Assert.Equal("test", target1.StrProp);
    Assert.Equal(5, target1.Add(2, 3));
    Assert.Equal("test", target2.StrProp);
    Assert.Equal(5, target2.Add(2, 3));
    
    // (参考)
    // モック化対象オブジェクトからモックオブジェクトの取得
    Mock<ITarget> target2Mock = Mock.Get(target2);
    target2Mock.Setup(o => o.Add(1, 2)).Returns(100);
    
    // テスト
    Assert.Equal("test", target2.StrProp);
    Assert.Equal(5, target2.Add(2, 3));
    Assert.Equal(100, target2.Add(1, 2));
  • 両者で作成される既定のモック化対象オブジェクトは微妙に異なるので注意が必要です。
    var target1Mock = new Mock<ITarget>();
    ITarget target1 = target1Mock.Object;
    
    ITarget target2 = Mock.Of<ITarget>();
    
    target1.StrProp = "test";
    Assert.Null(target1.StrProp); // 既定ではプロパティ値が保持されない
    
    target2.StrProp = "test";
    Assert.Equal("test", target2.StrProp);
    • new Mock<T>で作成されたモック化対象オブジェクトは、既定でプロパティが実装されていません。モック化対象オブジェクトのプロパティに値を設定しても保持されず、プロパティ値を読み取るとnullになります。
    • Mock.Of<T>()で作成されたモック化対象オブジェクトは、次のようにSetupAllProperties()で全てのプロパティが実装されています。モック化対象オブジェクトのプロパティに値が設定された場合、そのプロパティの値を後から取得することができます。詳細はGitHubのソースコードをご覧ください。
      public partial class Mock
      {
      	public static T Of<T>() where T : class
      	{
      		return Mock.Of<T>(MockBehavior.Default);
      	}
      	public static T Of<T>(MockBehavior behavior) where T : class
      	{
      		var mock = new Mock<T>(behavior);
      		if (behavior != MockBehavior.Strict)
      		{
      			mock.SetupAllProperties();
      		}
      		return mock.Object;
      	}