Как указать, что Arg<T>.Matches () не должен возвращать default(T)
У меня есть небольшая проблема с Rhino Mocks.
У меня есть абстрактный класс с методом, который ожидает объект (в примере ниже строки). Метод проверяет, является ли аргумент нулевым.
public abstract class Foo
{
public void DoSomething(string bar)
{
if (bar == null)
{
throw new ArgumentNullException("bar");
}
}
}
У меня есть другой класс, который использует Foo
:
public class Baz
{
private readonly Foo foo;
public Baz(Foo foo)
{
this.foo = foo;
}
public void DoWork(string s)
{
s = "xxx" + s;
this.foo.DoSomething(s);
}
}
Я хочу сделать юнит-тест и проверить, DoSomething
класса Foo
вызывается с правильным аргументом. я использовал Arg<T>.Matches()
за это.
[Test]
public void TestMethod()
{
var fooMock = MockRepository.GenerateMock<Foo>();
var objectUnderTest = new Baz(fooMock);
fooMock.Expect(x => x.DoSomething(Arg<string>.Matches(Text.StartsWith("xxx"))))
.Repeat.Once();
objectUnderTest.DoWork("hello");
fooMock.VerifyAllExpectations();
}
Теперь, когда я пытаюсь запустить этот тест, ArgumentNullException
на Expect(...)
Поднялся. Я посмотрел на код Rhino Mocks и обнаружил, что Match()
-Метод всегда возвращается default(T)
, который null
для строки (и любой другой класс). Так что проверка в DoSomething()
поднимает ArgumentNullException
,
Я знаю, что я мог бы извлечь интерфейс для Foo
и создайте макет этого интерфейса, чтобы не было нулевой проверки. Но я хочу знать, разрешима ли эта проблема с помощью Rhino Mocks, оставив код таким, какой он есть (за исключением, конечно, модульного теста;-)).
1 ответ
Проблема не решается только изменением тестового кода. Тестируемый код написан не для тестирования.
Причина в том, что Rhino Mock требует, чтобы метод mock /stubbed был перезаписан. Т.е. DoSomething()
должен быть либо интерфейсным методом (как вы описали в вопросе), либо виртуальным методом.
Если это было переопределено, то реальный метод DoSomething()
не будет запущен в течение Expect()
позвони вообще.
Оба варианта могут работать, но оба требуют изменения тестируемого кода.
Если это возможно изменить тестируемый код, то, по моему мнению, интерфейс использования, как IFoo
вместо абстрактного класса Foo
это предпочтительный способ. Поскольку это - то, как внедрение зависимости должно быть осуществлено должным образом.