Ответ 1
It.IsAny/It.Is
Это может быть полезно, когда вы передаете новый ссылочный тип в тестируемый код. Например, если у вас есть метод по строкам: -
public void CreatePerson(string name, int age) {
Person person = new Person(name, age);
_personRepository.Add(person);
}
Возможно, вы захотите проверить, что метод add был вызван в репозитории
[Test]
public void Create_Person_Calls_Add_On_Repository () {
Mock<IPersonRepository> mockRepository = new Mock<IPersonRepository>();
PersonManager manager = new PersonManager(mockRepository.Object);
manager.CreatePerson("Bob", 12);
mockRepository.Verify(p => p.Add(It.IsAny<Person>()));
}
Если вы хотите сделать этот тест более явным, вы можете использовать It.Is, поставив предикат, который должен соответствовать объекту person
[Test]
public void Create_Person_Calls_Add_On_Repository () {
Mock<IPersonRepository> mockRepository = new Mock<IPersonRepository>();
PersonManager manager = new PersonManager(mockRepository.Object);
manager.CreatePerson("Bob", 12);
mockRepository.Verify(pr => pr.Add(It.Is<Person>(p => p.Age == 12)));
}
Таким образом, тест будет проходить через исключение, если объект person, который использовался для вызова метода добавления, не имел возрастного свойства, установленного в 12.
Времена
Если у вас был метод по строкам: -
public void PayPensionContribution(Person person) {
if (person.Age > 65 || person.Age < 18) return;
//Do some complex logic
_pensionService.Pay(500M);
}
Одна из вещей, которые вы можете протестировать, заключается в том, что метод оплаты не вызывается, когда в метод передается человек старше 65 лет.
[Test]
public void Someone_over_65_does_not_pay_a_pension_contribution() {
Mock<IPensionService> mockPensionService = new Mock<IPensionService>();
Person p = new Person("test", 66);
PensionCalculator calc = new PensionCalculator(mockPensionService.Object);
calc.PayPensionContribution(p);
mockPensionService.Verify(ps => ps.Pay(It.IsAny<decimal>()), Times.Never());
}
Аналогичным образом можно представить ситуации, в которых вы выполняете итерацию по коллекции и вызывая метод для каждого элемента в коллекции, и вы хотели бы удостовериться, что это было вызвано определенным количеством раз, иначе вы просто просто Не заботьтесь.
SetupGet/SetupSet
Что вам нужно знать с этими парнями, так это то, что они отражают то, как ваш код взаимодействует с макетом, а не как настроить макет
public static void SetAuditProperties(IAuditable auditable) {
auditable.ModifiedBy = Thread.CurrentPrincipal.Identity.Name;
}
В этом случае код устанавливает свойство ModifiedBy экземпляра IAuditable, когда он получает свойство Name текущего экземпляра IPrincipal
[Test]
public void Accesses_Name_Of_Current_Principal_When_Setting_ModifiedBy() {
Mock<IPrincipal> mockPrincipal = new Mock<IPrincipal>();
Mock<IAuditable> mockAuditable = new Mock<IAuditable>();
mockPrincipal.SetupGet(p => p.Identity.Name).Returns("test");
Thread.CurrentPrincipal = mockPrincipal.Object;
AuditManager.SetAuditProperties(mockAuditable.Object);
mockPrincipal.VerifyGet(p => p.Identity.Name);
mockAuditable.VerifySet(a => a.ModifiedBy = "test");
}
В этом случае мы настраиваем свойство name на макет IPrincipal, чтобы он возвращал "тест", когда геттер вызывается в свойстве Name Identity, который мы не устанавливаем сами.
SetupProperty/SetupAllProperties
Глядя на тест выше, если он был изменен на чтение
[Test]
public void Accesses_Name_Of_Current_Principal_When_Setting_ModifiedBy() {
Mock<IPrincipal> mockPrincipal = new Mock<IPrincipal>();
Mock<IAuditable> mockAuditable = new Mock<IAuditable>();
mockPrincipal.SetupGet(p => p.Identity.Name).Returns("test");
var auditable = mockAuditable.Object;
Thread.CurrentPrincipal = mockPrincipal.Object;
AuditManager.SetAuditProperties(auditable);
Assert.AreEqual("test", auditable.ModifiedBy);
}
Тест завершится неудачно. Это связано с тем, что прокси, созданный Moq, на самом деле ничего не делает в установленном методе свойства, если вы его не скажете. В аффекте макет объекта выглядит примерно так:
public class AuditableMock : IAuditable {
public string ModifiedBy { get { return null; } set { } }
}
Чтобы пройти тест, вы должны сообщить Moq, чтобы настроить свойство на стандартное поведение свойства. Вы можете сделать это, вызвав SetupProperty, и макет будет больше похож на
public class AuditableMock : IAuditable {
public string ModifiedBy { get; set; }
}
и тест выше будет проходить, поскольку значение "тест" теперь будет храниться против макета. При запутывании сложных объектов вы можете сделать это для всех свойств, поэтому ярлык SetupAllProperties
Наконец, лампочка в IDE - это плагин resharper.