Как написать один модульный тест, который обрабатывает разные типы? - PullRequest
0 голосов
/ 29 апреля 2019

Я пишу тесты для своего дискорд-бота (используя XUnit) и хочу узнать, можно ли заменить мои тесты одним тестом.Если да, то как мне это сделать?

До сих пор я написал 4 модульных теста для своего класса Unity (который является оболочкой для Unity Container, DI framework).Эти тесты работают, как и ожидалось, но добавление нового теста каждый раз, когда я добавляю новый тип в контейнер, кажется неправильным.Я посмотрел ответы на похожие вопросы, но решения были сложными или бесполезными для моего случая.

Мой метод из класса Unity, который тестируется:

public static T Resolve<T>()
{
    return Container.Resolve<T>();
}

Возвращает экземплярсоответствующий тип из контейнера Unity.

Тесты:

[Fact]
public void ResolveIDataStorage_ShouldWork()
{
    var storage1 = Unity.Resolve<IDataStorage>();
    var storage2 = Unity.Resolve<IDataStorage>();

    Assert.NotNull(storage1);
    Assert.NotNull(storage2);
    Assert.Same(storage1, storage2);
}

[Fact]
public void ResolveILogger_ShouldWork()
{
    var logger1 = Unity.Resolve<ILogger>();
    var logger2 = Unity.Resolve<ILogger>();

    Assert.NotNull(logger1);
    Assert.NotNull(logger2);
    Assert.Same(logger1, logger2);
}

[Fact]
public void ResolveDiscordSocketClient_ShouldWork()
{
    var client1 = Unity.Resolve<DiscordSocketClient>();
    var client2 = Unity.Resolve<DiscordSocketClient>();

    Assert.NotNull(client1);
    Assert.NotNull(client2);
    Assert.Same(client1, client2);
}

[Fact]
public void ResolveConnection_ShouldWork()
{
    var con1 = Unity.Resolve<Connection>();
    var con2 = Unity.Resolve<Connection>();

    Assert.NotNull(con1);
    Assert.NotNull(con2);
    Assert.Same(con1, con2);
}

В каждом тесте я определяю некоторый тип и утверждаю, что два объекта не равны NULL и что они должны быть одним и тем же экземпляром.По сути, эти утверждения должны работать для любого типа (или для набора определенных типов, которые могут быть параметрами для теста [Теория]), поэтому, чтобы избежать вставки копий, было бы очень удобно иметь один тест.

Ответы [ 2 ]

3 голосов
/ 29 апреля 2019

Если ваша цель состоит в том, чтобы иметь один тест, который следует одному и тому же шаблону для каждого типа, который вы хотите проверить, вы можете извлечь тест в его собственный универсальный метод и просто вызвать его для каждого типа в рамках одного теста:

[Fact] 
public void Resolve_ShouldWork() 
{ 
    AssertResolvedTypesAreSame<IDataStorage>();
    AssertResolvedTypesAreSame<ILogger>();
    AssertResolvedTypesAreSame<DiscordSocketClient>();
    AssertResolvedTypesAreSame<Connection>();
}

private void AssertResolvedTypesAreSame<T>()
{
    var t1 = Unity.Resolve<T>(); 
    var t2 = Unity.Resolve<T>();

    Assert.NotNull(t1); 
    Assert.NotNull(t2); 
    Assert.Same(t1, t2); 
}
2 голосов
/ 29 апреля 2019

Используйте отражение, чтобы создать универсальный метод нужного типа, который нужно разрешить, и вызвать его.

Оттуда утверждают ожидаемое поведение.

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

Следующий пример основан на уже предоставленном коде.

[Theory]
[InlineData(typeof(IDataStorage))]
[InlineData(typeof(ILogger))]
[InlineData(typeof(DiscordSocketClient))]
[InlineData(typeof(Connection))]
public void Resolve_Singleton_Services_ShouldWork(Type type) {
    //Arrange
    var unityType = typeof(Unity);
    var resolve = unityType.GetMethod("Resolve", BindingFlags.Static| BindingFlags.Public);
    var genericResolve = resolve?.MakeGenericMethod(type);

    //Act
    var instance1 = genericResolve?.Invoke(null, null); // Unity.Resolve<type>()
    var instance2 = genericResolve?.Invoke(null, null); // Unity.Resolve<type>()

    //Assert
    Assert.NotNull(instance1);
    Assert.NotNull(instance2);
    Assert.Same(instance1, instance2);
}

Часть теста проверки размещения предполагает, что каждая конфигурация для контейнера уже была вызвана.

...