使用Moq对方法进行单元测试

时间:2012-05-25 19:13:50

标签: c# unit-testing moq

我正在尝试学习如何使用C#和Moq进行单元测试,并且我已经构建了一个小测试情况。鉴于此代码:

public interface IUser
{

    int CalculateAge();
    DateTime DateOfBirth { get; set; }
    string Name { get; set; }
}

public class User : IUser
{
    public DateTime DateOfBirth { get; set; }
    string Name { get; set; }

    public int CalculateAge()
    {
        return DateTime.Now.Year - DateOfBirth.Year;
    }
}

我想测试方法CalculateAge()。为此,我想我应该尝试在我的测试方法中为DateOfBirth属性提供一个默认值:

var userMock = new Mock<IUser>();
userMock.SetupProperty(u => u.DateOfBirth, new DateTime(1990, 3, 25)); //Is this supposed to give a default value for the property DateOfBirth ?
Assert.AreEqual(22, userMock.Object.CalculateAge());

但是当涉及到断言时,CalculateAge()的值等于0,尽管DateOfBirth等于new DateTime(1990, 3, 25)

我知道这可能看起来像一个愚蠢的例子,但无论如何......我以为我可以使用模拟为我的对象中尚未开发的方法/属性赋值,因此方法的测试不依赖于在我的类的另一个组件,甚至为我的对象设置默认上下文(因此这里的用户名...)我是否以错误的方式处理这个问题?

感谢。

2 个答案:

答案 0 :(得分:23)

是的,你接近错了,但不要担心,我会解释原因。第一个提示是

  

你可以完全删除你的User课程,一切都将成为   相同。

当你这样做时:

var userMock = new Mock<IUser>();

您只是创建了该接口的伪\模拟对象,它与您的初始User类无关,因此它没有CalculateAge方法的任何实现,除了假的只是愚蠢地返回0.这就是你在断言声明中得到0的原因。

所以,你说:

  

我认为我可以使用模拟来为尚未开发的人提供价值   我的对象中的方法/属性,因此方法的测试不会   依赖于我班级的另一个组成部分

你可以,假设你有一些IUser消费者,请说如下:

class ConsumerOfIUser
{
   public int Consume(IUser user)
   {
      return user.CalculateAge() + 10;
   }
}

在这种情况下,IUser的模拟将完全有意义,因为您想测试当{IUser.CalculateAge()返回10时ConsumerOfIUser的行为。您将执行以下操作:

var userMock = new Mock<IUser>();
userMock.Setup(u => u.CalculateAge()).Returns(10);

var consumer = new ConsumerOfIUser();
var result = consumer.Consume(userMock);

Assert.AreEqual(result, 20); //should be true

答案 1 :(得分:2)

这取决于您尝试测试的内容。在这种情况下,您已经模拟了User对象,因此在使用模拟对象替换它时,没有必要测试此类中的任何内容。如果你想测试User对象,那么你不应该嘲笑它。

模拟用于替换您不想测试的依赖对象。例如,如果你有一个Name对象而不是一个字符串(例如包含名字,姓氏,标题等),但是你不想测试Name对象,只是User对象,你会创建一个模拟的构造User对象时要使用的名称对象。