使用Moq模拟抽象类

时间:2014-05-27 05:46:46

标签: c# unit-testing moq

我有以下抽象类和测试方法。使用" Moq"我得到了以下错误:

我的Abstact课程:

   public abstract class UserProvider
{ 
    public abstract UserResponseObject CreateUser(UserRequestObject request, string userUrl);

    public abstract bool IsUserExist(UserRequestObject request, string userUrl);
}

测试类:

  [TestMethod()]
    public void CreateUserTest()
    {
        var mockUserProvider = new Mock<UserProvider>(MockBehavior.Loose);

    //GetUserRequestObject is local method to set data

         mockUserProvider.
            Setup(u => u.CreateUser(GetUserRequestObject(), ""))
            .Returns(new UserResponseObject { uid = "123", uri = userUri }).Verifiable();

         var userProvider = mockUserProvider.Object.CreateUser(GetUserRequestObject(), "");

         mockUserProvider.Verify(u => u.CreateUser(GetUserRequestObject(), ""));
    }

错误讯息:

  

Moq.MockException:模拟上的预期调用至少一次,但是   从未进行过:u =&gt; u.CreateUser(.GetUserRequestObject(),&#34;&#34;)

任何人都请解释一下,为什么我收到这条消息以及如何解决它?

4 个答案:

答案 0 :(得分:5)

您收到此错误的原因是因为您正在设置对象的特定实例的期望:

mockUserProvider.Verify(u => u.CreateUser(GetUserRequestObject(), ""));

这在很大程度上取决于方法的实现方式。 例如GetUserRequestObject()的此实现将在每次调用时创建一个新实例,并且验证将始终失败:

  private UserRequestObject GetUserRequestObject()
  {
     return new UserRequestObject();
  }

而为设置和验证返回相同的实例将成功:

  private UserRequestObject u = new UserRequestObject();
  private UserRequestObject GetUserRequestObject()
  {
     return u;
  }

您可以改为检查 Any 实例,而不是依赖于确切的实例(即避免比较2个引用):

mockUserProvider.Verify(u => u.CreateUser(It.IsAny<UserRequestObject>(),
                        It.IsAny<string>()), Times.Once);

或者最好是满足特定条件的实例(假设GetUserRequestObject()的属性Name设置为Bob

mockUserProvider.Verify(u => u.CreateUser(
                        It.Is<UserRequestObject>(x => x.Name == "Bob"),
                        It.Is<string>(s => s == "")));

答案 1 :(得分:1)

您的GetUserRequestObject()可能会返回UserRequestObject个对象的2个不同实例。

确保使用相同的实例来设置期望并通过调用进行验证。 (否则,在设定期望时使用It.IsAny<UserRequestObject>

答案 2 :(得分:1)

Moq检查对象的引用。您应该验证并传递与您在setup方法中使用的对象相同的对象:

public void CreateUserTest()
{
    var mockUserProvider = new Mock<UserProvider>(MockBehavior.Loose);

//GetUserRequestObject is local method to set data
     var user = GetUserRequestObject();

     mockUserProvider.
        Setup(u => u.CreateUser(user, ""))
        .Returns(new UserResponseObject { uid = "123", uri = userUri }).Verifiable();

     var userProvider = mockUserProvider.Object.CreateUser(user, "");

     mockUserProvider.Verify(u => u.CreateUser(user, ""));
}

或者,您可以检查传递给方法的任何对象:

public void CreateUserTest()
{
    var mockUserProvider = new Mock<UserProvider>(MockBehavior.Loose);

//GetUserRequestObject is local method to set data

     mockUserProvider.
        Setup(u => u.CreateUser(Is.Any<User>(), ""))
        .Returns(new UserResponseObject { uid = "123", uri = userUri }).Verifiable();

     var userProvider = mockUserProvider.Object.CreateUser(Is.Any<User>(), "");

     mockUserProvider.Verify(u => u.CreateUser(Is.Any<User>(), ""));
}

答案 3 :(得分:1)

非常简单 - 你正在做的一切正确,但你的验证是错误的。

您正在创建新的用户提供程序,但尚未指定将创建一个。

你需要使用它而不是空白:

mockUserProvider.
    Setup(u => u.CreateUser(new user, ""))
    .Returns(new UserResponseObject { uid = "123", uri = userUri }).Verifiable();

由此您需要在检查是否有新用户时纠正您的验证声明:

mockUserProvider.Verify(u => u.CreateUser(It.IsAny<User>()));

这意味着您实际上正在检查是否已创建用户实体,而在您未测试预期结果之前。它就像测试一些东西一样 - 比如你要创建一件你计划它的艺术作品并将其全部设置(你的模拟)。但你还不知道你将创造什么 - 所以在你的验证中你创造了艺术品并且需要验证它是某种类型的艺术而不仅仅是该方法已经运行,因为它返回了你没有检查的东西。