Intro:
Я использую AutoNSubstitute
в качестве фреймворка для автоматической проверки для моих тестов, чтобы дать cort'у sut возможность изменять сигнатуру без тестов на разрыв.Я обнаружил, что использование этого (или AutoFixture как инструмента создания sut вообще) не работает должным образом (или я не настроил его должным образом) при тестировании, что ctor обрабатывает свои аргументы, как и ожидалось.
Испытуемый объект: FileWriterFactory.FileWriterFactory ()
public class FileWriterFactory : IFileWriterFactory
{
private readonly Report _report;
private readonly IRepository _repository;
private readonly ILogFactory _logFactory;
public FileWriterFactory(Report report, IRepository repository, ILogFactory logFactory)
{
// the ctor is the sut
_report = report ?? throw new ArgumentNullException(nameof(report));
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
_logFactory = logFactory;
}
public IReportWritable GetWriter(ReportType type)
{
// not under test
}
}
Настройка теста:
[TestFixture]
public class Ctor
{
private Fixture _fixture;
[SetUp]
public void Setup()
{
_fixture = new Fixture();
_fixture.Behaviors.Add(new OmitOnRecursionBehavior());
_fixture.Customize(new AutoNSubstituteCustomization());
}
[Test]
public void NullRepo_Throws()
{
// arrange
_fixture.Customize<IRepository>(composer => composer.FromFactory(() => null));
// act
Action factory = () => _fixture.Create<FileWriterFactory>();
// assert
factory.Should().Throw<ArgumentNullException>();
}
}
Результат теста:
Expected a <System.ArgumentNullException> to be thrown, but found <AutoFixture.ObjectCreationExceptionWithPath>: "
"AutoFixture.ObjectCreationExceptionWithPath with message "AutoFixture was unable to create an instance from ComplianceTool.Common.FileWriterFactory because creation unexpectedly failed with exception. Please refer to the inner exception to investigate the root cause of the failure.
Request path:
ComplianceTool.Common.FileWriterFactory
Inner exception messages:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
System.ArgumentNullException: Value cannot be null.
Parameter name: repository
Понятно, что поведениеперехват исключений, генерируемых при вызове, существует, но как я могу настроить AutoFixture для перехвата TargetInvocationException
и выбросить его внутреннее исключение без дополнительной перехвата и обтекания его в ObjectCreationException
?
В настоящее время я работаю над этим безобразноНапример:
[Test]
public void NullRepo_Throws()
{
// arrange
_fixture.Customize<IRepository>(composer => composer.FromFactory(() => null));
// act
Action factory = () => _fixture.Build<FileWriterFactory>()
.WithoutExceptionHandling()
.Create();
// assert
factory.Should().Throw<ArgumentNullException>();
}
public static class FixtureExtensions
{
return composer.FromFactory(() =>
{
try
{
return composer.Create<T>();
}
catch (ObjectCreationException objectCreationException)
// allow exceptions from ctor to be unwrapped from their containing
{
if (objectCreationException.InnerException is TargetInvocationException targetInvocationException)
{
throw targetInvocationException.InnerException ??
new Exception("Could not find exception at the expected level");
}
throw;
}
catch (TargetInvocationException invocationException)
{
throw invocationException.InnerException ??
new Exception("Could not find exception at the expected level");
}
});
}
Но этот обходной путь дает мне неприятный вкус во рту и кажется хрупким.