Как вызывать метод модульного тестирования с расширением IConfiguration.Get <T> - PullRequest
1 голос
/ 13 марта 2019

У меня есть очень простой метод, который мне нужен для модульного тестирования.

public static class ValidationExtensions
{
    public static T GetValid<T>(this IConfiguration configuration)
    {
        var obj = configuration.Get<T>();
        Validator.ValidateObject(obj, new ValidationContext(obj), true);
        return obj;
    }
}

Проблема в том, что configuration.Get<T> является методом статического расширения и не относится к IConfiguration.Я не могу изменить реализацию этого статического метода.

Я думаю, возможно, самый простой способ - создать поставщика конфигурации памяти?Но я не знаю, смогу ли я создать его, не привязав его к веб-хостингу.

Ответы [ 2 ]

2 голосов
/ 13 марта 2019

Модуль конфигурации не зависит от функций, связанных с веб-хостингом.

Вы должны иметь возможность создавать конфигурацию в памяти для тестирования без необходимости привязывать ее к веб-хосту.

Просмотрите следующий пример теста

public class TestConfig {
    [Required]
    public string SomeKey { get; set; }
    [Required] //<--NOTE THIS
    public string SomeOtherKey { get; set; }
}

//...

[Fact]
public void Should_Fail_Validation_For_Required_Key() {
    //Arrange
    var inMemorySettings = new Dictionary<string, string>
    {
        {"Email:SomeKey", "value1"},
        //{"Email:SomeOtherKey", "value2"}, //Purposely omitted for required failure
        //...populate as needed for the test
    };

    IConfiguration configuration = new ConfigurationBuilder()
        .AddInMemoryCollection(inMemorySettings)
        .Build();

    //Act
    Action act = () => configuration.GetSection("Email").GetValid<TestConfig>();

    //Assert
    ValidationException exception = Assert.Throws<ValidationException>(act);
    //...other assertions of validation results within exception object
}

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

0 голосов
/ 13 марта 2019
[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        IConfiguration mock = new MockConfiguration();
        var simpleObject = mock.GetValid<SimpleObject>();
        Assert.AreEqual(simpleObject.MyConfigStr, "123");
    }
}

public class SimpleObject
{
    public string MyConfigStr { get; set; }
}


public class MockConfiguration : IConfiguration
{
    public IConfigurationSection GetSection(string key)
    {
        return new MockConfigurationSection()
        {
            Value = "123"
        };
    }

    public IEnumerable<IConfigurationSection> GetChildren()
    {
        var configurationSections = new List<IConfigurationSection>()
        {
            new MockConfigurationSection()
            {
                Value = "MyConfigStr"
            }
        };
        return configurationSections;
    }

    public Microsoft.Extensions.Primitives.IChangeToken GetReloadToken()
    {
        throw new System.NotImplementedException();
    }

    public string this[string key]
    {
        get => throw new System.NotImplementedException();
        set => throw new System.NotImplementedException();
    }
}

public class MockConfigurationSection : IConfigurationSection
{
    public IConfigurationSection GetSection(string key)
    {
        return this;
    }

    public IEnumerable<IConfigurationSection> GetChildren()
    {
        return new List<IConfigurationSection>();
    }

    public IChangeToken GetReloadToken()
    {
        return new MockChangeToken();
    }

    public string this[string key]
    {
        get => throw new System.NotImplementedException();
        set => throw new System.NotImplementedException();
    }

    public string Key { get; }
    public string Path { get; }
    public string Value { get; set; }
}

public class MockChangeToken : IChangeToken
{
    public IDisposable RegisterChangeCallback(Action<object> callback, object state)
    {
        return new MockDisposable();
    }

    public bool HasChanged { get; }
    public bool ActiveChangeCallbacks { get; }
}

public class MockDisposable : IDisposable
{
    public void Dispose()
    {
    }
}

создал макет для IConfiguration и имитировал поведение ConfigBinder

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Primitives;

добавил эти два пространства имен для его компиляции

...