【问题标题】:Unit testing a method with Moq使用 Moq 对方法进行单元测试
【发布时间】:2012-06-01 08:59:48
【问题描述】:

我正在尝试学习如何使用 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)。

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

谢谢。

【问题讨论】:

标签: c# unit-testing moq


【解决方案1】:

是的,你说错了,但别担心,我会解释原因。第一个提示是

您可以完全删除您的 User 课程,一切都将是 一样。

当你在做的时候:

var userMock = new Mock<IUser>();

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

所以,你是说:

认为我可以使用模拟来为尚未开发的产品赋予价值 我的对象中的方法/属性,因此方法的测试不会 依赖于我班级的另一个组件

您可以,假设您将有一些 IUser 的消费者,可以这样说:

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

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

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

【讨论】:

  • 那么在单独测试一个类时绝对没有理由使用 Mocking 吗?单独我的意思是与其他类没有交互。例如,假设我有一个下载一堆东西的方法,它需要 10 分钟才能运行。并且CalculateAge() 使用此方法返回的值...模拟此结果有用吗? (假设 DateOfBirth 是 10 分钟的下载方法,而不仅仅是一个自动属性)
  • @Pacane,没错。测试没有外部依赖的类(以最纯粹的形式)不需要模拟或存根。
  • 下载东西的方法应该写在另一个类中,可以模拟出来进行测试。
  • Pacane,是的,它会有意义,但是您应该将需要 10 分钟的属性设置为外部组件,这样您当前的课程就可以依赖它,这样您就可以模拟它.
  • @Stack0verflow,类似的东西,是的。单独测试接口并没有多大意义,因为不涉及任何逻辑。您可能想要测试的只是来自另一个类的该接口的组合,它正在传递适当的数据等。否则我认为您是正确的。
【解决方案2】:

这取决于您要测试的内容。在这种情况下,您已经模拟了 User 对象,因此在将其替换为模拟对象时,测试此类内部的任何内容都没有意义。如果你想测试 User 对象,那么你不应该模拟它。

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

【讨论】:

    猜你喜欢
    • 2021-10-15
    • 1970-01-01
    • 2020-09-06
    • 1970-01-01
    • 2011-12-24
    • 1970-01-01
    • 1970-01-01
    • 2011-01-30
    相关资源
    最近更新 更多