Запишите один метод класса и пусть другие реальные методы используют этот пронумерованный
У меня есть класс TimeMachine
, который предоставляет мне текущие значения даты/времени. Класс выглядит следующим образом:
public class TimeMachine
{
public virtual DateTime GetCurrentDateTime(){ return DateTime.Now; };
public virtual DateTime GetCurrentDate(){ return GetCurrentDateTime().Date; };
public virtual TimeSpan GetCurrentTime(){ return GetCurrentDateTime().TimeOfDay; };
}
Я хотел бы использовать TimeMachine
stub в своих тестах таким образом, чтобы я просто заглушил метод GetCurrentDateTime
, а другие 2 метода использовали обрезанный метод GetCurrentDateTime
, так как у меня нет чтобы заглушить все три метода. Я попытался написать тест следующим образом:
var time = MockRepository.GenerateStub<TimeMachine>();
time.Stub(x => x.GetCurrentDateTime())
.Return(new DateTime(2009, 11, 25, 12, 0, 0));
Assert.AreEqual(new DateTime(2009, 11, 25), time.GetCurrentDate());
Но тест терпит неудачу. GetCurrentDate
возвращает default(DateTime)
вместо использования GetCurrentDateTime
заглушки внутри.
Есть ли какой-нибудь подход, который я мог бы использовать для достижения такого поведения, или это просто базовая концептуальная функция RhinoMocks, которую я сейчас не поймаю? Я знаю, что могу просто избавиться от этих двух методов GetDate
/Time
и включить использование .Date
/.TimeOfDay
, но я хотел бы понять, возможно ли это вообще.
Ответы
Ответ 1
Я только выяснил, что это можно достичь, не используя виртуальные по этим двум методам - он защищает методы от переопределения при создании заглушки.
public class TimeMachine
{
public virtual DateTime GetCurrentDateTime(){ return DateTime.Now; };
public DateTime GetCurrentDate(){ return GetCurrentDateTime().Date; };
public TimeSpan GetCurrentTime(){ return GetCurrentDateTime().TimeOfDay; };
}
Теперь проходит тест.
Ответ 2
Измените TimeMachine
на абстрактный класс:
public abstract class TimeMachine
{
public abstract DateTime GetCurrentDateTime();
public DateTime GetCurrentDate(){ return GetCurrentDateTime().Date; };
public TimeSpan GetCurrentTime(){ return GetCurrentDateTime().TimeOfDay; };
}
Для производственных целей вы можете создать конкретную реализацию TimeMachine
следующим образом:
public class SystemTimeMachine : TimeMachine
{
public override DateTime GetCurrentDateTime()
{
return DateTime.Now;
}
}
Теперь все классы, потребляющие TimeMachine
, могут быть добавлены абстракцией, но в процессе производства вы можете привязать свой графический объект к SystemTimeMachine
.
Ответ 3
Если метод помечен как virtual
, Stub не будет вызывать оригинальный метод, даже если вы не запустили метод. Вы можете заставить RhinoMocks вызвать исходный метод, выполнив:
var time = MockRepository.GenerateStub<TimeMachine>();
time.Stub(x => x.GetCurrentDateTime()).Return(new DateTime(2009, 11, 25, 12, 0, 0));
time.Stub(x => x.GetCurrentDate()).CallOriginalMethod(OriginalCallOptions.NoExpectation);
Assert.AreEqual(new DateTime(2009, 11, 25), time.GetCurrentDate());
Это третья (отдельная) строка, которая заставляет RhinoMocks вызывать базовый, оригинальный метод.
Ответ 4
Штук просто предоставляет консервированные ответы на вызовы метода и свойств, он ничего не знает о фактической реализации TimeMachine. Боюсь, вам нужно будет настроить результаты для каждого из трех методов (или для конкретного метода, который вы хотите протестировать).
Ответ 5
Я не уверен, какую версию Rhino.Mocks вы используете, но я бы сделал только виртуальный метод GetCurrentDateTime() (например, предложенный более ранний плакат), а затем создайте свой макет с помощью PartialMock(), Есть много способов установить вещи, но следующее должно работать:
var mocks = new MockRepository();
var time = mocks.PartialMock<TimeMachine>();
using (mocks.Record())
{
Expect.Call(time.GetCurrentDateTime()).Return(new DateTime(2009, 11, 25, 12, 0, 0));
}
using (mocks.Playback())
{
Assert.AreEqual(new DateTime(2009, 11, 25), time.GetCurrentDate());
}