2012-05-25 4 views
16

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

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

Спасибо.

+1

* Действительно * хорошая статья, которая выравнивается параллельно с вашим вопросом: http://kakimotonline.com/2011/01/02/unit-testing-net-application-with-moq-framework/ – atconway

ответ

23

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

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

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

var userMock = new Mock<IUser>(); 

Вы просто создать поддельный \ фиктивный объект этого интерфейса, который не имеет ничего общего с вашим начальным 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 
+0

Так что нет абсолютно никакой причины использовать Mocking при тестировании одного класса? Один я имею в виду, что нет никакого взаимодействия с другими классами. Например, допустим, у меня есть метод, который загружает кучу вещей, и для выполнения требуется 10 минут. И что CalculateAge() использует значение, возвращаемое этим методом ... Было бы полезно выполнить Mock этот результат? (Предположим, что DateOfBirth - это способ загрузки 10 минут, а не просто авто-свойство) – Pacane

+4

@Pacane, это верно. Тестирование класса без внешних зависимостей (в чистом виде) не должно требовать макета или заглушки. – lbergnehr

+2

Метод загрузки материала должен быть написан в другом классе, который может быть изделен для тестирования. – Ben

2

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

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

Смежные вопросы