В xUnit/Shouldly/AutoMoq/Autofixture мы можем передать тип, используя InlineAutoMoqData, который можно использовать как <T> в самом тесте?

У меня есть проблема в модульном тестировании, которую я не смог решить. Я думаю, что самый краткий способ сказать это:

Я хочу иметь возможность использовать Тип, предоставленный в параметрах Теории InlineAutoMoqData, как T в методе Должно Должно. Это позволило бы мне создавать различные тесты строк (я полагаю, что в этой структуре это встроенные теории), ожидающие различные типы исключений, если с методом связано несколько объектов.

Я не уверен, возможно ли это, но вот пример самого модульного теста.

[Theory]
[InlineAutoMoqData("bork", typeof(FileTypeNotRecognizedException))]
public void Build_ReturnsSpecificException_FileNamePassedIn(string fileName, Type expected, ProcessFactory sut)
{
    Should.Throw<expected>(() => sut.Build(fileName));
}

Перед тем, как озадачиться и опубликовать это, я рассмотрел следующие вопросы: динамически создать универсальный тип для шаблона и создать экземпляр универсального типа с переменной, содержащей тип

Возможно ли что-то подобное?

Редактировать:

Я вижу, что в xUnit я могу добиться этого с помощью метода Assert.Throws(Type, Delegate).

[Theory]
[InlineAutoMoqData("bork", typeof(FileTypeNotRecognizedException))]
public void Build_ReturnsSpecificException_FileNamePassedIn(string fileName, Type expected, ProcessFactory sut)
{
    Assert.Throws(expected, () => sut.Build(fileName));
}

Я все еще хотел бы знать, есть ли способ достигнуть этого всякий раз, когда я хочу, чтобы Тип был в Обобщенном Методе.

1 ответ

Вы не можете, кроме использования Reflection, похожи на две ссылки, которые вы упомянули.

Тем не менее, вы можете сделать маленький трюк, чтобы добиться того, что вы хотите. Это уродливо и непрактично, и я не рекомендую использовать его, но просто для удовольствия...

Создайте универсальный класс, содержащий ваш параметризованный тест:

public class Test<T> where T : Exception
{
    public virtual void Build_ReturnsSpecificException_FileNamePassedIn(
        string fileName,
        ProcessFactory sut)
    {
        Assert.Throws<T>(() => sut.Build(fileName));
    }
}

Для каждого параметра (тип исключения) вы создаете класс, унаследованный от общего, переопределяете метод теста и используете InlineAutoMoqData:

public class TestFileNotFound : Test<FileTypeNotRecognizedException>
{
    [Theory]
    [InlineAutoMoqData("bork")]
    public override void Build_ReturnsSpecificException_FileNamePassedIn(string fileName,
        ProcessFactory sut)
    {
        base.Build_ReturnsSpecificException_FileNamePassedIn(fileName, sut);
    }
}
public class TestAnotherException : Test<Exception>
{
    [Theory]
    [InlineAutoMoqData("borg")]
    public override void Build_ReturnsSpecificException_FileNamePassedIn(string fileName,
        ProcessFactory sut)
    {
        base.Build_ReturnsSpecificException_FileNamePassedIn(fileName, sut);
    }
}

Конечно, вы можете сделать то же самое, используя универсальный метод вместо универсального класса, но это тоже выглядит глупо:

public void Build_ReturnsSpecificException_FileNamePassedIn<TException>(string fileName,
    ProcessFactory sut)
    where TException : Exception
{
    Assert.Throws<TException>(() => sut.Build(fileName));
}

[Theory]
[InlineAutoMoqData("bork")]
public void Build_ReturnsSpecificException_FileNamePassedIn(string fileName,
    ProcessFactory sut)
{
    Build_ReturnsSpecificException_FileNamePassedIn<FileTypeNotRecognizedException>(fileName, sut);
}

[Theory]
[InlineAutoMoqData("borg")]
public void Build_ReturnsAnotherException_FileNamePassedIn(string fileName,
    ProcessFactory sut)
{
    Build_ReturnsSpecificException_FileNamePassedIn<Exception>(fileName, sut);
}

Как вы обнаружили, xUnit.net имеет неуниверсальный Assert.Throws это занимает Type и вы должны использовать это вместо этого взломать.

Другие вопросы по тегам