Moq - Как проверить, что значение свойства задано с помощью установщика
Рассмотрим этот класс:
public class Content
{
public virtual bool IsCheckedOut {get; private set;}
public virtual void CheckOut()
{
IsCheckedOut = true;
}
public virtual void CheckIn()
{
//Do Nothing for now as demonstrating false positive test.
}
}
Метод Checkin намеренно пуст. Теперь у меня есть несколько методов тестирования, чтобы проверить статус вызова каждого метода.
[TestMethod]
public void CheckOutSetsCheckedOutStatusToTrue()
{
Content c = new Content();
c.CheckOut();
Assert.AreEqual(true, c.IsCheckedOut); //Test works as expected
}
[TestMethod]
public void CheckInSetsCheckedOutStatusToFalse()
{
Content c = new Content();
c.CheckIn();
Assert.AreEqual(false, c.IsCheckedOut); //Test does not work as expected
}
Второй тест проходит по неправильным причинам. Итак, как я могу использовать mocking (moq), чтобы проверить, что CheckIn устанавливает свойство IsCheckedOut?
Спасибо.
ИЗМЕНИТЬ
Чтобы уточнить: у меня есть метод, называемый CheckIn(), задачей которого является установить статус IsCheckedOut на false.
Вы увидите в моем тестовом коде выше, что Test вернет false, даже если я не установил значение свойства false; Ожидается, что здесь ничего плохого.
Я думаю, что мой вопрос конкретно: Как я могу проверить, что метод CheckIn() установил для свойства IsCheckedOut значение false? Это то, что я бы назвал поведенческой проверкой.
Я считаю, что некоторые из комментариев предлагают сделать что-то, что соответствует государственной проверке? Если это так, я не верю, что есть какая-либо ценность в том, чтобы насмехаться над этой частью вообще, когда мы можем просто использовать:
Content c = new Content();
c.CheckIn();
Assert.AreEqual(false, c.IsCheckedOut); //State verification
Конечно, я могу ошибаться, поэтому, пожалуйста, помогите мне прояснить эти понятия:)
Ответы
Ответ 1
Следующее должно работать. Настройте свой макет как:
var mock=new Mock<IContent>();
mock.SetupSet(content => content.IsCheckedOut=It.IsAny<bool>()).Verifiable();
И после тестового кода:
mock.VerifySet(content => content.IsCheckedOut=It.IsAny<bool>());
Я все равно не тестировал его, поэтому, пожалуйста, скажите мне, работает ли оно для вас.
ИЗМЕНИТЬ. Действительно, это не сработает, поскольку установщик для IsCheckedOut
является ложным.
В любом случае, теперь я вижу, что вы никогда не устанавливаете значение IsCheckedOut
во время построения класса. Было бы неплохо добавить следующее к классу Content
:
public Content()
{
IsCheckedOut=false;
}
Ответ 2
Mock mockContect = new Mock<Cotent>();
mockContent.VerifySet(x => x.IsCheckedOut, Times.Once());
Будет ли это трюк? Не знаете, как входит частный сеттер, чтобы играть так, как это было проверено. но работает для моего публичного сеттера.
Получите это от: http://www.codethinked.com/post/2009/03/10/Beginning-Mocking-With-Moq-3-Part-2.aspx
Ответ 3
почему бы вам просто не настроить начальный контент? Помните, что вы проверяете поведение функции CheckIn.
[TestMethod]
public void CheckInSetsCheckedOutStatusToFalse()
{
// arrange - create a checked out item
Content c = new Content();
c.CheckOut();
// act - check it in
c.CheckIn();
// assert - IsCheckedOut should be set back to false
Assert.AreEqual(false, c.IsCheckedOut);
}
Ответ 4
Могу ли я предположить, что вы можете подумать об этом не так - как правило, вы должны что-то настраивать, выполнять действие, а затем проверять поведение (результат). В этом случае действительно имеет значение, что установщик не задал значение false - важно иметь в виду, что он является ложным после того, как был реализован данный сценарий. Если вы проводите тесты изолированно, это может показаться немного странным, но для чего-либо ваши тесты будут существовать в наборах.
Ситуация была бы иной, если бы вы тестировали взаимодействие между двумя классами - тогда было бы хорошо настроить ожидаемое значение для средства настройки свойств, поскольку действие настройки - это взаимодействие, которое вы тестируете.
Я не знаком с Moq, поскольку я использую Rhino.Mocks - но я предполагаю, что будет что-то вроде mock.VerifySet(content = > content.IsCheckedOut = It.IsEqual(true));
Ответ 5
Я согласен с вами: насмешка не имеет значения в этом сценарии, потому что она предназначена для проверки взаимодействия между вашим классом (тестированием) и остальным миром, а не для проверки внутреннего механизма вашего класса.
Я думаю, что этот тест
Content c = new Content();
c.CheckIn();
Assert.AreEqual(false, c.IsCheckedOut); //State verification
который вы пишете, имеет смысл и не является ложным положительным! Вы должны убедиться, что состояние было таким образом после CheckIn независимо от того, почему это так; если в будущем вы укажете состояние в конструкторе (или другими способами), этот тест сохранит вас, и вы будете вынуждены внедрить метод CheckIn!
В некоторых случаях, подобных вашему, я хочу установить начальное состояние, чтобы быть уверенным, что я не забываю реализовать метод CheckIn; в этом случае я использую 2 метода (первый очень уродливый):
- Я вызываю c.CheckOut() до c.CheckIn(); это очень уродливо, потому что
вы проверяете 2 метода вместо одного... но я признаю, что я написал нечто похожее
несколько раз: -)
- Я делаю приватный сеттер защищенным, и я пишу тестовый класс, который
наследуется от тестируемого класса; таким образом, я могу установить
свойство true, чтобы вызвать c.CheckIn(), чтобы убедиться, что
метод выполняет свою работу.
Вот код:
public class Content2
{
public virtual bool IsCheckedOut { get; protected set; }
public virtual void CheckOut()
{
IsCheckedOut = true;
}
public virtual void CheckIn()
{
//Do Nothing for now as demonstrating false positive test.
}
}
[TestClass]
public class Content2Test : Content2
{
[TestMethod]
public void CheckOutSetsCheckedOutStatusToTrue()
{
this.CheckOut();
Assert.AreEqual(true, this.IsCheckedOut); //Test works as expected
}
[TestMethod]
public void CheckInSetsCheckedOutStatusToFalse()
{
this.IsCheckedOut = true;
this.CheckIn();
Assert.AreEqual(false, this.IsCheckedOut); //Test does not work as expected
}
}
Надеюсь помочь.