Как смоделировать ConfigurationManager.AppSettings с помощью moq - PullRequest
107 голосов
/ 28 февраля 2012

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

ConfigurationManager.AppSettings["User"];

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

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

Ответы [ 7 ]

139 голосов
/ 19 февраля 2014

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

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

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

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

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

97 голосов
/ 28 февраля 2012

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

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

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

21 голосов
/ 28 февраля 2012

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

14 голосов
/ 08 августа 2013

Вы можете использовать прокладки для изменения 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 Fakes . Надеюсь это поможет.

8 голосов
/ 29 июля 2014

Рассматривали ли вы заглушки вместо насмешек? Свойство 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, пока она вам действительно не понадобится.

2 голосов
/ 28 февраля 2012

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

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

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

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

1 голос
/ 21 января 2016

Я думаю, что написание собственного провайдера 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; } }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...