У меня есть часть устаревшего кода, который я хочу протестировать. Вот репродукция основных моментов:
public class LegacyUnit
{
private readonly ICollaborator collaborator;
public LegacyUnit(ICollaborator collaborator)
{
this.collaborator = collaborator;
}
public object GetStuff(HttpContextBase context, string input)
{
try
{
if (input == "")
{
context.Response.End();
}
collaborator.DoOtherStuff();
return "Done!";
}
catch (ThreadAbortException)
{ }
return null;
}
}
У этого устаревшего устройства есть некоторые проблемы, но пока я просто пытаюсь его протестировать. В частности, я хочу проверить, что collaborator.DoOtherStuff
не вызывается, если Response.End()
вызывает ThreadAbort
.
Проблема: как вызвать такое исключение?
Я прочитал этот вопрос и ответы на него на ThreadAbortException
и понял, что он особенный. Однако из этих сообщений я не вижу, как справиться с этим в модульных тестах.
Вот моя попытка:
[Test]
public void DoesNotCallCollaboratorOnThreadAbort()
{
var testResponseMock = new Mock<HttpResponseBase>();
var testContextMock = new Mock<HttpContextBase>();
var collaboratorMock = new Mock<ICollaborator>();
testContextMock.Setup(x => x.Response).Returns(testResponseMock.Object);
testResponseMock.Setup(x => x.End()).Throws<ThreadAbortException>(); // Compile error
var unit = new LegacyUnit(collaboratorMock.Object);
unit.GetStuff(testContextMock.Object, "");
collaboratorMock.Verify(c => c.DoOtherStuff(), Times.Never);
}
Очевидно, компилятор жалуется: ThreadAbortException
не имеет доступного конструктора. Кроме того, это sealed
(вероятно, по уважительным причинам), поэтому создание «тестируемого» подкласса не сработает.
Каков правильный способ получить такой код для тестирования? Возможно ли это вообще, или LegacyUnit
слишком недружелюбен к тестам?
Полное минимальное воспроизведение (пустая библиотека классов .NET 4.5 с NUnit 2.6.4 и Moq 4.5.9):
public interface ICollaborator
{
void DoOtherStuff();
}
public class LegacyUnit
{
private readonly ICollaborator collaborator;
public LegacyUnit(ICollaborator collaborator)
{
this.collaborator = collaborator;
}
public object GetStuff(HttpContextBase context, string input)
{
try
{
if (input == "") context.Response.End();
collaborator.DoOtherStuff();
return "Done!";
}
catch (ThreadAbortException)
{ }
return null;
}
}
[TestFixture]
public class LegacyUnitTests
{
[Test]
public void DoesNotCallCollaboratorOnThreadAbort()
{
var testResponseMock = new Mock<HttpResponseBase>();
var testContextMock = new Mock<HttpContextBase>();
var collaboratorMock = new Mock<ICollaborator>();
testContextMock.Setup(x => x.Response).Returns(testResponseMock.Object);
testResponseMock.Setup(x => x.End()).Throws<ThreadAbortException>(); // Compile error here
var unit = new LegacyUnit(collaboratorMock.Object);
unit.GetStuff(testContextMock.Object, "");
collaboratorMock.Verify(c => c.DoOtherStuff(), Times.Never);
}
}