Как обмануть ConfigurationManager.AppSettings с moq

Я застрял в этой точке кода, что не знаю, как насмехаться:

ConfigurationManager.AppSettings["User"];

Мне нужно высмеять ConfigurationManager, но у меня нет подсказки, я использую Moq.

Кто-нибудь может дать мне совет? Спасибо!

Ответ 1

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

Итак, вы бы обернули ConfigurationManager. Что-то вроде:

public class Configuration: IConfiguration
{
    public User
    {
        get{ 
               return ConfigurationManager.AppSettings["User"];
       }
    }
}

(Вы можете просто извлечь интерфейс из своего класса конфигурации, а затем использовать этот интерфейс повсюду в своем коде) Тогда вы просто издеваетесь над IConfiguration. Возможно, вы сможете реализовать сам фасад несколькими способами. Выше я решил просто обернуть отдельные свойства. Вы также получаете преимущество, заключающееся в том, чтобы иметь строго типизированную информацию для работы с, а не слабо типизированными массивами хешей.

Ответ 2

Я использую AspnetMvc4. Момент назад я написал

ConfigurationManager.AppSettings["mykey"] = "myvalue";

в моем тестовом методе, и он отлично работал.

Объяснение: метод тестирования выполняется в контексте с настройками приложения, взятыми из, как правило, web.config или myapp.config. ConfigurationsManager может достичь этого глобального объекта-приложения и управлять им.

Хотя: Если у вас параллельно работает тестовый бегун, это не очень хорошая идея.

Ответ 3

Возможно, это не то, что вам нужно выполнить, но считаете ли вы, что используете приложение app.config в своем тестовом проекте? Таким образом, ConfigurationManager получит значения, которые вы добавили в app.config, и вам не нужно ничего издеваться. Это решение работает хорошо для моих нужд, потому что мне никогда не нужно тестировать "переменный" файл конфигурации.

Ответ 4

Вы можете использовать прокладки, чтобы изменить AppSettings на пользовательский объект NameValueCollection. Вот пример того, как вы можете это сделать:

[TestMethod]
public void TestSomething()
{
    using(ShimsContext.Create()) {
        const string key = "key";
        const string value = "value";
        ShimConfigurationManager.AppSettingsGet = () =>
        {
            NameValueCollection nameValueCollection = new NameValueCollection();
            nameValueCollection.Add(key, value);
            return nameValueCollection;
        };

        ///
        // Test code here.
        ///

        // Validation code goes here.        
    }
}

Вы можете больше узнать о прокладках и подделках, Изолировать код под тестом с подделками Microsoft. Надеюсь это поможет.

Ответ 5

Вы считали, что вместо того, чтобы насмехаться? Свойством AppSettings является NameValueCollection:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        // Arrange
        var settings = new NameValueCollection {{"User", "Otuyh"}};
        var classUnderTest = new ClassUnderTest(settings);

        // Act
        classUnderTest.MethodUnderTest();

        // Assert something...
    }
}

public class ClassUnderTest
{
    private readonly NameValueCollection _settings;

    public ClassUnderTest(NameValueCollection settings)
    {
        _settings = settings;
    }

    public void MethodUnderTest()
    {
        // get the User from Settings
        string user = _settings["User"];

        // log
        Trace.TraceInformation("User = \"{0}\"", user);

        // do something else...
    }
}

Преимущества - это более простая реализация и отсутствие зависимости от System.Configuration, пока вам это не понадобится.

Ответ 6

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

Для насмешливой статики я использую инструмент Moles, который является бесплатным. Существуют и другие средства выделения изоляции, такие как Typemock, которые тоже могут это сделать, хотя я считаю, что это платные инструменты.

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

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

Ответ 7

Я думаю, что написать собственный поставщик app.config - простая задача и более полезная, чем что-либо еще. Особенно вам следует избегать любых подделок, таких как прокладки и т.д., Потому что, как только вы их используете, Edit и Continue больше не работают.

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

По умолчанию они получают значения из App.config, но для модульных тестов я могу переопределить все значения и использовать их в каждом тесте самостоятельно.

Нет необходимости в каких-либо интерфейсах или реализовывать его каждый раз снова и снова. У меня есть утилита dll и использую этот небольшой помощник во многих проектах и ​​модульных тестах.

public class AppConfigProvider
{
    public AppConfigProvider()
    {
        ConnectionStrings = new ConnectionStringsProvider();
        AppSettings = new AppSettingsProvider();
    }

    public ConnectionStringsProvider ConnectionStrings { get; private set; }

    public AppSettingsProvider AppSettings { get; private set; }
}

public class ConnectionStringsProvider
{
    private readonly Dictionary<string, string> _customValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

    public string this[string key]
    {
        get
        {
            string customValue;
            if (_customValues.TryGetValue(key, out customValue))
            {
                return customValue;
            }

            var connectionStringSettings = ConfigurationManager.ConnectionStrings[key];
            return connectionStringSettings == null ? null : connectionStringSettings.ConnectionString;
        }
    }

    public Dictionary<string, string> CustomValues { get { return _customValues; } }
}

public class AppSettingsProvider
{
    private readonly Dictionary<string, string> _customValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

    public string this[string key]
    {
        get
        {
            string customValue;
            return _customValues.TryGetValue(key, out customValue) ? customValue : ConfigurationManager.AppSettings[key];
        }
    }

    public Dictionary<string, string> CustomValues { get { return _customValues; } }
}