Jawaban:
Saya percaya satu pendekatan standar untuk ini adalah dengan menggunakan fasad pola untuk membungkus manajer konfigurasi dan kemudian Anda memiliki sesuatu yang digabungkan secara longgar yang dapat Anda kendalikan.
Jadi, Anda akan membungkus ConfigurationManager. Sesuatu seperti:
public class Configuration: IConfiguration
{
public User
{
get
{
return ConfigurationManager.AppSettings["User"];
}
}
}
(Anda bisa mengekstrak antarmuka dari kelas konfigurasi Anda dan kemudian menggunakan antarmuka itu di mana-mana dalam kode Anda) Kemudian Anda hanya mengejek IConfiguration. Anda mungkin dapat menerapkan fasad itu sendiri dengan beberapa cara berbeda. Di atas saya memilih hanya untuk membungkus properti individu. Anda juga mendapatkan keuntungan tambahan karena memiliki informasi yang diketik dengan kuat untuk digunakan daripada array hash yang diketik lemah.
var configurationMock = new Mock<IConfiguration>();
dan untuk penyiapan:configurationMock.SetupGet(s => s.User).Returns("This is what the user property returns!");
Saya menggunakan AspnetMvc4. Beberapa saat yang lalu saya menulis
ConfigurationManager.AppSettings["mykey"] = "myvalue";
dalam metode pengujian saya dan itu bekerja dengan sempurna.
Penjelasan: metode pengujian berjalan dalam konteks dengan pengaturan aplikasi yang diambil dari, biasanya a web.config
atau myapp.config
.ConfigurationsManager
dapat mencapai objek application-global ini dan memanipulasinya.
Meskipun: Jika Anda memiliki runner pengujian yang menjalankan pengujian secara paralel, ini bukanlah ide yang baik.
ConfigurationManager.AppSettings
adalah NameValueCollection
yang tidak aman untuk thread, jadi pengujian paralel yang menggunakannya tanpa sinkronisasi yang tepat bukanlah ide yang baik. Jika tidak, Anda hanya dapat memanggil ConfigurationManager.AppSettings.Clear()
di Anda TestInitialize
/ ctor dan Anda sedang emas.
Mungkin bukan itu yang perlu Anda capai, tetapi apakah Anda pernah mempertimbangkan untuk menggunakan app.config dalam proyek pengujian Anda? Jadi ConfigurationManager akan mendapatkan nilai yang Anda masukkan ke app.config dan Anda tidak perlu meniru apa pun. Solusi ini berfungsi dengan baik untuk kebutuhan saya, karena saya tidak perlu menguji file konfigurasi "variabel".
Web.config
proyek yang mencakup. Selama pengujian, menarik beberapa nilai terkenal dari app.config
itu sangat valid. Tes unit hanya perlu memastikan kondisi saat menarik mengatakan "cluster1" berfungsi; hanya ada 4 cluster berbeda dalam kasus ini.
Anda dapat menggunakan shims untuk memodifikasi objek AppSettings
khusus NameValueCollection
. Berikut adalah contoh bagaimana Anda bisa mencapai ini:
[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.
}
}
Anda dapat membaca selengkapnya tentang shims dan fakes di, Isolating Code Under Test with Microsoft Fakes . Semoga ini membantu.
Apakah Anda pernah mempertimbangkan untuk menghina daripada mengejek? The AppSettings
properti adalah 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...
}
}
Manfaatnya adalah implementasi yang lebih sederhana dan tidak bergantung pada System.Configuration sampai Anda benar-benar membutuhkannya.
IConfiguration
seperti yang disarankan Joshua Enfield bisa jadi level yang terlalu tinggi, dan Anda mungkin melewatkan bug yang ada karena hal-hal seperti penguraian nilai konfigurasi yang buruk. Di sisi lain, menggunakan ConfigurationManager.AppSettings
secara langsung seperti yang disarankan LosManos adalah terlalu banyak detail implementasi, belum lagi hal itu dapat memiliki efek samping pada pengujian lain dan tidak dapat digunakan dalam pengujian paralel tanpa sinkronisasi manual (karena NameValueConnection
tidak aman untuk thread).
Itu adalah properti statis, dan Moq dirancang untuk metode instance Moq atau kelas yang dapat diejek melalui pewarisan. Dengan kata lain, Moq tidak akan membantu Anda di sini.
Untuk mengejek statika, saya menggunakan alat yang disebut Mol , yang gratis. Ada alat isolasi kerangka kerja lainnya, seperti Typemock yang dapat melakukan ini juga, meskipun saya yakin itu adalah alat berbayar.
Ketika datang ke statika dan pengujian, opsi lain adalah membuat sendiri keadaan statis, meskipun ini sering kali bisa menjadi masalah (seperti, saya membayangkan itu akan terjadi dalam kasus Anda).
Dan, akhirnya, jika kerangka isolasi bukanlah pilihan dan Anda berkomitmen pada pendekatan ini, fasad yang disebutkan oleh Joshua adalah pendekatan yang baik, atau pendekatan apa pun secara umum di mana Anda memfaktorkan kode klien ini jauh dari logika bisnis yang Anda gunakan. sedang digunakan untuk menguji.
Saya pikir menulis penyedia app.config Anda sendiri adalah tugas yang sederhana dan lebih berguna daripada yang lainnya. Terutama Anda harus menghindari pemalsuan seperti shims dll karena segera setelah Anda menggunakannya Edit & Lanjutkan tidak berfungsi lagi.
Penyedia yang saya gunakan terlihat seperti ini:
Secara default, mereka mendapatkan nilai dari App.config
tetapi untuk pengujian unit, saya dapat mengganti semua nilai dan menggunakannya di setiap pengujian secara independen.
Tidak perlu antarmuka apa pun atau menerapkannya setiap kali berulang kali. Saya memiliki dll utilitas dan menggunakan pembantu kecil ini di banyak proyek dan unit tes.
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; } }
}
Bagaimana dengan hanya mengatur apa yang Anda butuhkan? Karena, saya tidak ingin mengejek NET, apakah saya ...?
System.Configuration.ConfigurationManager.AppSettings["myKey"] = "myVal";
Anda mungkin harus membersihkan AppSettings sebelumnya untuk memastikan aplikasi hanya melihat apa yang Anda inginkan.