Я использую стандартную реализацию Model-View-Presenter в приложении ASP.NET WebForms.Мое представление имеет два следующих события: одно указывает, что пользователь заполнил достаточно полей в модели домена, чтобы инициировать проверку дублирования, а другое - обычное событие сохранения.Мой псевдокод выглядит следующим образом:
public class ItemNewPresenter : PresenterBase<IItemNewView>
{
public IItemService Service { get; private set; }
public IItemNewView View { get; private set; }
public ItemNewPresenter(IItemService service, IItemNewView view)
{
Service = service;
View = view;
View.OnSave += DoItemSave;
View.OnItemIsDuplicateCheck+= DoItemIsDuplicateCheck;
}
private void DoItemIsDuplicateCheck(object sender, CheckItemDuplicateEventArgs e)
{
CheckForItemDuplication(e.Item);
}
private void CheckForItemDuplication(Item item){
if (Service.IsDuplicateItem(item))
{
View.RedirectWithNotification(BuildItemUrl(item), "This item already exists");
}
}
private void DoItemSave(object sender, SaveItemEventArgs e)
{
DoItemIsDuplicateCheck(this, e.ToItemDuplicateEventArgs());
Service.Save(e.Item);
}
}
Вот мой тест, чтобы убедиться, что мой докладчик ведет себя правильно, когда OnItemIsDuplicateCheck поднимается из представления:
[Test]
public void presenter_checking_for_existing_item_should_call_redirect_if_found()
{
var service = new Mock<IItemService>();
var view = new Mock<IItemNewView>();
var presenter = new ItemNewPresenter (service.Object, view.Object);
var onCheckExistingHandler = view.CreateEventHandler <CheckItemDuplicateEventArgs>();
view.Object.OnExistingDenominatorCheck += onCheckExistingHandler;
var eventArgs = new CheckItemDuplicateEventArgs();
service.Setup(s => s.IsDuplicate(It.Is<CheckItemDuplicateEventArgs>(c => c.Equals(eventArgs)))).Returns(true);
onCheckExistingHandler.Raise(eventArgs);
view.Verify(v => v.RedirectWithNotification(It.IsAny<String>(), It.IsAny<string>()), Times.Once());
service.Verify();
}
Для согласованности я хотел быиметь такую же проверку дубликатов, когда View вызывает событие OnSave
.Мой вопрос заключается в том, как мне написать свой тест, когда один из методов, которые я хочу проверить (CheckForItemDuplication
), объявлен в тестируемом классе.Альтернативой проверке вызова метода в SUT (плохо) было бы написать мой тест сохранения с лотов дублированного кода (настройка и утверждение всех моих mock будет скопировано из вышеупомянутого теста), и это такжеделает модульный тест менее сфокусированным.
[Test]
public void presenter_saving_item_should_check_for_dupe_and_save_if_not_one() {
//duplicate mocks/setups/asserts from duplicate check fixture
//additional mocks/setups/asserts to test save logic
}
Я думаю, TDD предложил бы вытащить этот закрытый метод из отдельного класса, который работает с моим Presenter и будет вводиться через DI.Но добавление еще одной зависимости к моему Presenter для функциональности, которая не заслуживает того, чтобы быть автономной абстракцией * и * представляет внутреннюю деталь реализации моего Presenter, кажется ... ну ... сумасшедшей.Я здесь далеко от базы?Должен быть какой-то шаблон проектирования или рефакторинг, который я могу применить, чтобы избежать необходимости превращать закрытый метод в зависимость.