Moq ile ConfigurationManager.AppSettings ile nasıl alay edilir


124

Nasıl alay edeceğimi bilmediğim bu kod noktasında sıkışıp kaldım:

ConfigurationManager.AppSettings["User"];

ConfigurationManager ile dalga geçmem gerekiyor, ancak bir fikrim yok, Moq kullanıyorum .

Biri bana bir ipucu verebilir mi? Teşekkürler!

Yanıtlar:


105

Buna standart bir yaklaşımın , konfigürasyon yöneticisini sarmak için bir cephe modeli kullanmak olduğuna inanıyorum ve daha sonra üzerinde kontrol sahibi olduğunuz gevşek bir şekilde bağlanmış bir şeye sahipsiniz.

Böylece ConfigurationManager'ı sarmalayabilirsiniz. Gibi bir şey:

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

(Yapılandırma sınıfınızdan bir arabirim çıkarabilir ve ardından bu arabirimi kodunuzun her yerinde kullanabilirsiniz) Ardından, IConfiguration ile dalga geçersiniz. Cephenin kendisini birkaç farklı şekilde uygulayabilirsiniz. Yukarıda sadece bireysel mülkleri sarmayı seçtim. Ayrıca, zayıf yazılmış karma diziler yerine çalışmak için güçlü bir şekilde yazılmış bilgilere sahip olmanın yan avantajını da elde edersiniz.


6
Ben de kavramsal olarak bunu yapıyorum. Ancak, arayüzün uygulanmasını anında oluşturan Castle DictionaryAdapter ( Castle Core'un bir parçası ) kullanıyorum. Bunun hakkında bir süre önce yazmıştım : blog.andreloker.de/post/2008/09/05/… (Castle DictionaryAdapter'ı nasıl kullandığımı görmek için "Bir Çözüm" e kaydırın)
Andre Loker

Bu şık ve bu iyi bir makale. Bunu gelecek için aklımda tutmam gerekecek.
Joshua Enfield

Ayrıca ekleyebilirim - sizin sadeliğinize ve yorumlarınıza bağlı olarak - bunun yerine Temsilci Proxy veya Adaptör olarak da adlandırılabilir.
Joshua Enfield

3
Yukarıdan Moq'u "normal" olarak kullanıyor. Test edilmedi, ancak şöyle bir şey: var configurationMock = new Mock<IConfiguration>();ve kurulum için:configurationMock.SetupGet(s => s.User).Returns("This is what the user property returns!");
Joshua Enfield

Bu senaryo, bir katman IConfiguration'a bağlı olduğunda ve IConfiguration ile dalga geçmeniz gerektiğinde kullanılır, ancak IConfiguration Implementation'ı nasıl test edersiniz? Ve eğer bir Unit Test ConfigurationManager.AppSettings ["Kullanıcı"] 'yı çağırırsanız, bu üniteyi test etmez, ancak konfigürasyon dosyasından hangi değerlerin alındığını test eder ki bu bir ünite testi değildir. Uygulamayı kontrol etmeniz gerekirse, bkz. @ Zpbappi.com/testing-codes-with-configurationmanager-appsettings
nkalfov

174

AspnetMvc4 kullanıyorum. Bir dakika önce yazdım

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

benim test yöntemimde ve mükemmel çalıştı.

Açıklama: Test yöntemi, tipik olarak a web.configveya myapp.config. ConfigurationsManagerbu uygulama genel nesnesine ulaşabilir ve onu işleyebilir.

Yine de: Testleri paralel olarak çalıştıran bir test çalıştırıcınız varsa, bu iyi bir fikir değildir.


8
Bu, sorunu çözmenin gerçekten zekice ve basit bir yoludur! Sadelik için tebrikler!
Navap

1
Çoğu durumda bir soyutlama oluşturmaktan çok daha kolay
Michael Clark

2
Bu kadar???? Bu özel mühürlü sınıfı nasıl test edeceğime dair beynimi harap ettiğim için parlaklık basitlikte.
Piotr Kula

6
ConfigurationManager.AppSettingsBir olduğunu NameValueCollectionparçacığı için güvenli değil, hangi uygun senkronizasyon bırakmadan kullanmayı o kadar paralel testler zaten iyi bir fikir değildir. Aksi takdirde sadece çağırabilir ConfigurationManager.AppSettings.Clear()senin içinde TestInitializesen altın / ctor ve.
Ohad Schneider

1
Basit ve öz. Açık ara en iyi cevap!
znn

21

Belki başarmanız gereken şey bu değildir, ancak test projenizde bir app.config kullanmayı düşündünüz mü? Böylece ConfigurationManager, app.config dosyasına koyduğunuz değerleri alır ve hiçbir şeyle alay etmenize gerek kalmaz. Bu çözüm ihtiyaçlarım için iyi çalışıyor çünkü "değişken" bir yapılandırma dosyasını asla test etmem gerekmiyor.


7
Test edilen kodun davranışı bir yapılandırma değerinin değerine bağlı olarak değişirse, doğrudan AppSettings'e bağlı değilse onu test etmek kesinlikle daha kolaydır.
Andre Loker

2
Diğer olası ayarları asla test etmediğiniz için bu kötü bir uygulamadır. Joshua Enfield'ın cevabı test etmek için harika.
mkaj

4
Diğerleri bu yanıta karşı çıkarken, konumlarının biraz genel olduğunu söyleyebilirim. Bu, bazı senaryolarda çok geçerli bir cevaptır ve gerçekten ihtiyaç duyduğunuz şeye bağlıdır. Örneğin, her biri farklı bir temel URL'ye sahip 4 farklı kümem olduğunu varsayalım. Bu 4 küme, çalışma süresi boyunca Web.config, projeyi çevreleyen kısımdan çekilir . Test sırasında, iyi bilinen bazı değerleri almak app.configçok geçerlidir. Birim testi, "cluster1" i çektiği zaman koşulların çalıştığından emin olmalıdır; bu durumda sadece 4 farklı küme vardır.
Mike Perrenoud

14

AppSettingsÖzel bir NameValueCollectionnesneye değiştirmek için şimler kullanabilirsiniz . İşte bunu nasıl başarabileceğinize dair bir örnek:

[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 ile Test Altında İzole Etme Kodu sayfasında şimler ve sahte ürünler hakkında daha fazla bilgi edinebilirsiniz . Bu yardımcı olur umarım.


6
Yazar MS Fakes hakkında değil, adedi ile nasıl yapılır soruyor.
JPCF

6
Ve bu nasıl farklı? Veri bağımlılığını kodundan kaldırarak alay etmeyi başarır. C # Fakes kullanmak bir yaklaşımdır!
Zorayr

9

Alay etmek yerine saplamayı düşündün mü? AppSettingsTesiste olduğu 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...
    }
}

Faydaları, daha basit bir uygulama ve gerçekten ihtiyacınız olana kadar System.Configuration'a bağımlılık olmamasıdır.


3
Bu yaklaşımı en çok seviyorum. Bir yandan, yapılandırma yöneticisini IConfigurationJoshua Enfield'in önerdiği gibi bir ile sarmak çok yüksek düzeyde olabilir ve kötü yapılandırma değeri ayrıştırma gibi şeyler nedeniyle var olan hataları gözden kaçırabilirsiniz. Öte yandan, ConfigurationManager.AppSettingsLosManos'un önerdiği gibi doğrudan kullanmak çok fazla bir uygulama ayrıntısıdır, diğer testler üzerinde yan etkilere sahip olabileceğinden ve manuel senkronizasyon olmadan paralel test çalışmalarında kullanılamayacağından bahsetmiyorum bile ( NameValueConnectioniş parçacığı güvenli değildir).
Ohad Schneider

2

Bu statik bir özelliktir ve Moq, miras yoluyla alay edilebilen Moq örnek yöntemleri veya sınıfları için tasarlanmıştır. Başka bir deyişle, Moq burada size herhangi bir yardımcı olmayacak.

Statiği alay etmek için , ücretsiz olan Moles adlı bir araç kullanıyorum . Typemock gibi bunu yapabilen başka çerçeve izolasyon araçları da var, ancak bunların ücretli araçlar olduğuna inanıyorum.

Statik ve test söz konusu olduğunda, başka bir seçenek de statik durumu kendiniz oluşturmaktır, ancak bu genellikle sorunlu olabilir (sizin durumunuzda olacağını tahmin ediyorum).

Ve son olarak, izolasyon çerçeveleri bir seçenek değilse ve bu yaklaşıma bağlıysanız, Joshua'nın bahsettiği dış görünüş iyi bir yaklaşımdır veya genel olarak bunun müşteri kodunu hesaba kattığınız iş mantığından uzak tuttuğunuz herhangi bir yaklaşımdır. test etmek için kullanıyoruz.


1

Kendi app.config sağlayıcınızı yazmak basit bir iştir ve diğer her şeyden daha yararlıdır. Özellikle şim vb. Sahtekarlıklardan kaçınmalısınız çünkü bunları kullandığınız anda Düzenle ve Devam Et çalışmıyor.

Kullandığım sağlayıcılar şuna benziyor:

Varsayılan olarak değerleri 'den alırlar, App.configancak birim testleri için tüm değerleri geçersiz kılabilir ve her testte bağımsız olarak kullanabilirim.

Herhangi bir arayüze veya her defasında tekrar tekrar uygulamaya gerek yoktur. Bir yardımcı program dll var ve bu küçük yardımcıyı birçok proje ve birim testinde kullanıyorum.

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; } }
}

1

İhtiyacınız olanı ayarlamaya ne dersiniz? Çünkü .NET ile dalga geçmek istemiyorum, değil mi ...?

System.Configuration.ConfigurationManager.AppSettings["myKey"] = "myVal";

Uygulamanın yalnızca istediğiniz şeyi gördüğünden emin olmak için muhtemelen Uygulama Ayarları'nı önceden temizlemelisiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.