Единичное тестирование метода с помощью Moq - программирование
Подтвердить что ты не робот

Единичное тестирование метода с помощью Moq

Я пытаюсь научиться делать модульное тестирование с помощью С# и 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).

Я знаю, что это может показаться глупым примером, но что угодно... Я думал, что могу использовать насмешку, чтобы придать значения еще не разработанному методу/свойствам в моих объектах, поэтому тестирование метода не будет зависеть на другой компонент моего класса или даже настроить контекст по умолчанию для моего объекта (отсюда и имя пользователя здесь...) Я приближаюсь к этой проблеме неправильным образом?

Спасибо.

4b9b3361

Ответ 1

Да, вы ошибаетесь, но не волнуйтесь, я объясню, почему. Первый намек был бы

вы можете полностью удалить свой класс User, и все будет то же самое.

Когда вы делаете:

var userMock = new Mock<IUser>();

Вы просто создаете поддельный\mock-объект этого интерфейса, который не имеет ничего общего с вашим начальным классом User, поэтому он не имеет никакой реализации метода CalculateAge, кроме фальшивого, который просто глупо возвращает 0. Вот почему вы получаете 0 в заявлении assert.

Итак, вы говорили:

думал, что я мог бы насмехаться, чтобы дать ценности еще не разработанным метод/свойства в моих объектах, поэтому тестирование метода не будет зависят от другого компонента моего класса

Вы можете сказать, что у вас будет некоторый потребитель вашего IUser, скажем так:

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

в этом случае mocking 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

Ответ 2

Это зависит от того, что вы пытаетесь проверить. В этом случае вы издеваетесь над объектом User, поэтому нет смысла тестировать что-либо внутри этого класса, поскольку вы заменяете его макетным объектом. Если вы хотите протестировать объект User, вам не следует издеваться над этим.

Mocks используются для замены зависимых объектов, которые вы не хотите тестировать. Например, если у вас был объект Name вместо строки (например, содержит имя, фамилию, заголовок и т.д.), Но вы не захотите протестировать объект Name, только объект User, вы создадите макет Имя объекта, который будет использоваться при создании объекта User.