2009-07-08 2 views
3

Пример:Убедитесь, что ни один метод, или другой был вызван в модульном тесте

public bool Save(MyObj instance) 
{ 
    if (instance.IsNew) 
    { 
     this.repository.Create(instance); 
    } 
    else 
    { 
     this.repository.Update(instance); 
    } 
} 

Как создать тест в Moq, который проверяет:

  1. что свойство IsNew является который был отправлен
  2. , что либо Create(), либо Update() было использовано

ответ

2

К сожалению, у меня есть решение самостоятельно.

Все, что вам нужно сделать, это иметь локальную переменную int, которую вы установите на 0, а затем насмехаетесь, увеличивая ее. В конце вы должны проверить, больше ли его имя больше 0 (или точно 1, в зависимости от проблемы).

// Arrange 
int count = 0; 
Mock<Repository> mock = new Mock<Repository>(); 
mock.Setup<bool>(m => m.Create(It.IsAny<MyObj>())).Callback(() => count++); 
mock.Setup<bool>(m => m.Update(It.IsAny<MyObj>())).Callback(() => count++); 
// Act 
... 
// Assert 
Assert.AreEqual(count, 1); 

Было бы два теста. Тот, который устанавливает свойство IsNew на true и тот, который устанавливает его на false.

+0

См. Мой обновленный ответ ниже. В целом вы должны попытаться выразить свои ожидания как можно яснее. С помощью Moq это можно эффективно выполнить с помощью методов Verifiable и Verify. Это было бы более явным. Для обычных пользователей Moq это также было бы то, что они ожидали бы, поэтому тест, написанный таким образом, был бы более разборчивым, чем ваше решение. –

+0

Havent используется Подтверждаемый ранее. Отлично. Я попытаюсь увидеть разницу. –

3

Off верхней части моей головы: Проверка, что IsNew свойство читается:

var mock = new Mock<MyObj>(); 
mock.Setup(m => m.IsNew).Returns(true).Verifiable(); 
//... 
sut.Save(mock.Object); 
//... 
mock.Verify(); 

В приведенном выше примере, IsNew свойство вернет true, поэтому Создать путь будет принято.

Чтобы убедиться, что был вызван метод Create или Update, вам необходимо подключиться к этой функции. Похоже, что репозиторий является статическим классом, и в этом случае вы не можете заменить его тестовым двойным, но я, возможно, неправильно читаю ваш код ... Если вы можете заменить его тестовым двойным (Mock) вы можете использовать тот же принцип, что и выше.

Если вы можете проверить состояние своего репозитория после вызова метода Save, то вы можете проверить с помощью State-Based Testing, какой из двух путей кода следовать.

Если нет внешнее наблюдение разница между результатом двух путей кода, вероятно, лучше не тестировать эту конкретную деталь реализации. Это может привести вас к анти-шаблону под названием Overspecified Test - вы можете узнать больше об этом анти-шаблоне и многих других предметах, связанных с тестированием, в отличной книге xUnit Test Patterns.


Edit: Проверка хранилищ может быть сделано таким же образом:

var myObjMock = new Mock<MyObj>(); 
myObjMock.Setup(m => m.IsNew).Returns(true); 

var repositoryMock = new Mock<Repository>(); 
repositoryMock.Setup(m => m.Create(myObjMock.Object)).Verifiable(); 

var sut = new SomeClass(repositoryMock.Object); 
sut.Save(myObjMock.Object); 

repositoryMock.Verify(); 

Вызов Верифицируемые является ключевым. Без этого поведение Moq по умолчанию - это уйти с пути, сделать все возможное и не бросать никаких исключений, если это вообще возможно.

Когда вы вызываете Verifiable, вы поручаете макету ожидать этого конкретного поведения. Если это ожидание не было выполнено, когда вы вызываете Verify, он генерирует исключение и, таким образом, терпит неудачу.

+0

Я изменил код для своего репозитория. Это был только код. Это не предназначалось для репозитория Singleton. На самом деле у меня есть интерфейс, поэтому я могу добавить свой репозиторий в экземпляр объекта objet (перегрузка конструктора). –

+0

Я добавил Подтверждаемый() внутри моего теста. Но нет никакой разницы, когда ожидания не будут выполнены. Я всегда получаю то же исключение. –