Как использовать Machine.Fakes, чтобы конструктор не вызывал локальный метод?
Учитывая конструктор, который должен выдать исключение:
public class MyObject
{
public MyObject(String name)
{
if (String.IsNullOrEmpty(name))
throw new ArgumentNullException("name");
this.Initialize();
}
protected virtual void Initialize()
{
// do stuff
}
}
Как бы я использовал Machine.Fakes с Rhino (по умолчанию, и я перехожу на Rhino), чтобы смоделировать этот класс и проверить, что:
- Выдает ожидаемое исключение
- Это не вызывает Initialize()
С Moq я могу смоделировать сам класс MyObject и установить свойство на макете Callbase = true
заставить его вести себя как нормальный класс.
Затем я могу проверить, что было сгенерировано исключение, и что метод не был вызван с этим:
// all pseudo code to prove my point of "creating an instance"
//
void when_creating_new_MyObject_with_null_Name_should_throw_Exception()
{
// arrange
Mock<MyObject> myObjectToTest = new Mock<MyObject>(String.Empty);
myObjectToTest.Callbase = true;
// act
Assert.Throws<ArgumentNullException>(() =>
var instance = myObjectToTest.Object;
);
}
void when_creating_new_MyObject_with_null_Name_should_not_call_Initialize()
{
// arrange
Mock<MyObject> myObjectToTest = new Mock<MyObject>(String.Empty);
myObjectToTest.Callbase = true;
// act
try
{
// creates an instance
var instance = myObjectToTest.Object;
}
catch {}
// assert
myObjectToTest.Verify(x => x.Initialize(), Times.Never());
}
Но у меня возникают проблемы с выяснением, как использовать MSpec с Fakes для макета этого:
[Subject(typeof(MyObject), "when instantiating a new instance")
class with_null_Name
{
static MyObject myObjectToTest;
static Exception expectedException;
Establish context =()=>
myObjectToTest = An<MyObject>(String.Empty);
Because of; // I don't think there is anything to act on here?
It should_throw_Exception;
// how to capture exception with An<T>()?
It should_not_call_Initialize = () =>
myObjectToTest.WasNotToldTo(x => x.Initialize());
}
Я знаю и использую Catch.Exception(...)
обычно в моем Because of
действует. Но этот вариант использования, похоже, не работает с этим.
Любые указатели будут оценены.
Спасибо!
Отказ от ответственности: Реальный вариант использования довольно сложен с тяжелыми объектами для инициализации, что довольно дорого с кэшированными вспомогательными элементами. Приведенный выше код является просто упрощенной версией.
2 ответа
Лично я не привык использовать фальшивые фреймворки для насмешек в тестируемом модуле. Я использую mocks, чтобы сломать внешние зависимости, используя внедрение зависимости. Я ни в коем случае не эксперт в этом, но мое интуитивное чувство - то, что это слишком мелкая деталь, чтобы проверить.
Вы говорите, что в вашей реальной ситуации есть много объектов для инициализации; Не могли бы вы высмеять один или несколько из этих объектов и проверить, что они не вызваны? Или используйте инъекцию зависимостей, чтобы внедрить некоторый поддельный объект, в котором вы можете установить флаг.
Эти предложения кажутся мне вонючими. В конце концов, вы знаете, если вы сгенерировали исключение, что Initialize не был вызван. Я думаю, я понимаю, что вы пытаетесь убедиться, что ошибка не появится в будущем редактировании, но вы на самом деле тестируете здесь разработчика? Лично я бы подумал, что достаточно убедиться, что при выдаче неверных данных выдается исключение. Мне интересно услышать любые разные мнения, хотя.
Для меня нет смысла тестировать издеваться sut
, фиктивное поведение определяется вами в тестовом методе. Вы должны проверить реальный объект.
В этом случае вы должны проверять, что исключение выдается только при предоставлении неверных данных.
Я думаю, вы знаете, как это сделать, но в любом случае вот код:
[Subject(typeof (MyObject), "when instantiating a new instance")]
internal class with_null_Name
{
static MyObject myObjectToTest;
static Exception expectedException;
Because of = () => expectedException = Catch.Exception(
() => myObjectToTest = new MyObject(String.Empty));
It should_fail = () => expectedException.ShouldNotBeNull();
}