简体   繁体   English

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

[英]Unit testing a method with Moq

I'm trying to learn how to do Unit testing with C# and Moq, and I've built a little test situation. 我正在尝试学习如何使用C#和Moq进行单元测试,并且我已经构建了一个小测试情况。 Given this code: 鉴于此代码:

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;
    }
}

I want to test the method CalculateAge() . 我想测试方法CalculateAge() To do this, I thought I should try giving a default value to the DateOfBirth property by doing this in my test method: 为此,我想我应该尝试通过在我的测试方法中执行此操作,为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());

But when It comes to the assertion, the value of CalculateAge() equals 0, although DateOfBirth equals new DateTime(1990, 3, 25) . 但是当涉及到断言时, CalculateAge()的值等于0,尽管DateOfBirth等于new DateTime(1990, 3, 25) DateOfBirth new DateTime(1990, 3, 25)

I know this may look like a silly example, but whatever... I thought I could use mocking to give values to not-yet-developed method/properties in my objects, so the testing of a method wouldn't depend on another component of my class, or even setting up a default context for my object (hence the name of the user here...) Am I approaching this problem the wrong way? 我知道这可能看起来像一个愚蠢的例子,但无论如何......我想我可以使用模拟为我的对象中尚未开发的方法/属性赋值,因此方法的测试不依赖于另一个组件我的班级,甚至为我的对象设置默认上下文(因此这里的用户名称......)我是否以错误的方式处理这个问题?

Thanks. 谢谢。

Yes, you approaching it wrong, but don't worry, I'll explain why. 是的,你接近错了,但不要担心,我会解释原因。 First hint would be 第一个提示是

you can completely remove your User class and everything will be the same. 你可以完全删除你的User类,一切都是一样的。

When you are doing: 当你这样做时:

var userMock = new Mock<IUser>();

You just creating a fake\\mock object of that interface, that has nothing to do with your initial User class, so it doesn't have any implementation of CalculateAge method, except of fake one that just silly returns 0. That's why you are getting 0 in your assert statement. 你只是创建了一个与该初始User类无关的该接口的假\\模拟对象,因此它没有任何CalculateAge方法的实现,除了假的只是愚蠢的返回0.这就是你得到的原因断言语句中为0。

So, you were saying: 所以,你说:

thought I could use mocking to give values to not-yet-developed method/properties in my objects, so the testing of a method wouldn't depend on another component of my class 以为我可以使用mocking为我的对象中尚未开发的方法/属性赋值,因此方法的测试不依赖于我的类的另一个组件

You could, let's say you will have some consumer of your IUser, lets say like the following: 你可以,假设你有一些IUser的消费者,让我们说如下:

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

in that case mocking of IUser will make total sense, since you want to test how your ConsumerOfIUser behaves when IUser.CalculateAge() returns 10. You would do the following: 在这种情况下,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

It depends on what your trying to test. 这取决于你试图测试的内容。 In this case, you have mocked out the User object, so there is no point in testing anything inside this class as you are replacing it with a mock object. 在这种情况下,您已经模拟了User对象,因此在使用模拟对象替换它时,没有必要测试此类中的任何内容。 If you want to test the User object then you shouldn't mock it out. 如果你想测试User对象,那么你不应该嘲笑它。

Mocks are used to replace dependant objects that you don't want to test. 模拟用于替换您不想测试的依赖对象。 For example, if you had a Name object instead of a string (eg contains first name, surname, title etc..) but you didn't want to test the Name object, just the User object, you would create a mock of the Name object to be used when constructing the User object. 例如,如果你有一个Name对象而不是一个字符串(例如包含名字,姓氏,标题等),但是你不想测试Name对象,只是User对象,你会创建一个模拟的构造User对象时要使用的名称对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM