คำตอบ:
ฉันเชื่อว่าแนวทางมาตรฐานวิธีหนึ่งในการนี้คือการใช้รูปแบบซุ้มเพื่อรวมตัวจัดการการกำหนดค่าจากนั้นคุณจะมีบางสิ่งที่ควบคู่กันไปอย่างหลวม ๆ ซึ่งคุณสามารถควบคุมได้
ดังนั้นคุณจะห่อ ConfigurationManager สิ่งที่ต้องการ:
public class Configuration: IConfiguration
{
public User
{
get
{
return ConfigurationManager.AppSettings["User"];
}
}
}
(คุณสามารถแยกอินเทอร์เฟซจากคลาสคอนฟิกูเรชันของคุณจากนั้นใช้อินเทอร์เฟซนั้นได้ทุกที่ในโค้ดของคุณ) จากนั้นคุณก็ล้อเลียน IConfiguration คุณอาจสามารถใช้ส่วนหน้าได้หลายวิธี ด้านบนฉันเลือกที่จะรวมคุณสมบัติแต่ละอย่างไว้ นอกจากนี้คุณยังได้รับประโยชน์จากการมีข้อมูลที่พิมพ์มากเพื่อใช้งานได้แทนที่จะพิมพ์อาร์เรย์แฮชที่พิมพ์ผิด
var configurationMock = new Mock<IConfiguration>();
และสำหรับการตั้งค่า:configurationMock.SetupGet(s => s.User).Returns("This is what the user property returns!");
ฉันใช้ AspnetMvc4 เมื่อสักครู่ที่ผ่านมาฉันเขียน
ConfigurationManager.AppSettings["mykey"] = "myvalue";
ในวิธีการทดสอบของฉันและทำงานได้อย่างสมบูรณ์
คำอธิบาย: วิธีการทดสอบทำงานในบริบทที่มีการตั้งค่าแอพที่นำมาจากโดยทั่วไปคือweb.config
หรือmyapp.config
. ConfigurationsManager
สามารถเข้าถึงวัตถุทั่วโลกของแอปพลิเคชันและจัดการกับมัน
แม้ว่า: หากคุณมีนักวิ่งทดสอบวิ่งทดสอบควบคู่กันไปนี่ไม่ใช่ความคิดที่ดี
ConfigurationManager.AppSettings
เป็นสิ่งNameValueCollection
ที่ไม่ปลอดภัยต่อเธรดดังนั้นการทดสอบแบบขนานโดยใช้การซิงโครไนซ์ที่เหมาะสมจึงไม่ใช่ความคิดที่ดี มิฉะนั้นคุณสามารถโทรConfigurationManager.AppSettings.Clear()
เข้าTestInitialize
/ ctor ของคุณและคุณเป็นสีทอง
อาจไม่ใช่สิ่งที่คุณต้องทำให้สำเร็จ แต่คุณคิดจะใช้ app.config ในโครงการทดสอบของคุณหรือไม่ ดังนั้น ConfigurationManager จะได้รับค่าที่คุณใส่ไว้ใน app.config และคุณไม่จำเป็นต้องเยาะเย้ยอะไร วิธีนี้ใช้ได้ดีกับความต้องการของฉันเพราะฉันไม่จำเป็นต้องทดสอบไฟล์ config "ตัวแปร"
Web.config
โปรเจ็กต์ที่ล้อมรอบ ในระหว่างการทดสอบการดึงค่าที่รู้จักกันดีจากค่าapp.config
นั้นใช้ได้มาก การทดสอบหน่วยเพียงแค่ต้องตรวจสอบให้แน่ใจว่าเงื่อนไขเปิดเมื่อดึงออกมาว่า "cluster1" ทำงานได้ ในกรณีนี้มีคลัสเตอร์ที่แตกต่างกันเพียง 4 กลุ่มเท่านั้น
คุณสามารถใช้ shims เพื่อปรับเปลี่ยน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.
}
}
คุณสามารถอ่านเพิ่มเติมเกี่ยวกับการชิมและปลอมที่, Isolating รหัสภายใต้การทดสอบกับ Microsoft ปลอม หวังว่านี่จะช่วยได้
คุณเคยคิดว่าการลอกเลียนแบบแทนที่จะล้อเลียนหรือไม่? 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 จนกว่าคุณจะต้องการจริงๆ
IConfiguration
ตามที่ Joshua Enfield แนะนำอาจเป็นระดับที่สูงเกินไปและคุณอาจพลาดข้อบกพร่องที่มีอยู่เนื่องจากสิ่งต่างๆเช่นการแยกวิเคราะห์ค่าการกำหนดค่าที่ไม่ถูกต้อง ในทางกลับกันการใช้ConfigurationManager.AppSettings
โดยตรงตามที่ LosManos แนะนำเป็นรายละเอียดการใช้งานมากเกินไปไม่ต้องพูดถึงอาจมีผลข้างเคียงกับการทดสอบอื่น ๆ และไม่สามารถใช้ในการทดสอบแบบขนานโดยไม่ต้องซิงโครไนซ์ด้วยตนเอง (เนื่องจากNameValueConnection
เธรดไม่ปลอดภัย)
นั่นคือคุณสมบัติคงที่และ Moq ได้รับการออกแบบมาเพื่อวิธีการอินสแตนซ์ Moq หรือคลาสที่สามารถล้อเลียนผ่านการสืบทอด กล่าวอีกนัยหนึ่ง Moq จะไม่ช่วยอะไรคุณที่นี่
สำหรับการเยาะเย้ยสถิตฉันใช้เครื่องมือที่เรียกว่าโมลซึ่งฟรี มีเครื่องมือแยกเฟรมเวิร์กอื่น ๆ เช่น Typemock ที่สามารถทำได้เช่นกันแม้ว่าฉันเชื่อว่าเป็นเครื่องมือที่ต้องชำระเงิน
เมื่อพูดถึงสถิตยศาสตร์และการทดสอบอีกทางเลือกหนึ่งคือการสร้างสถานะคงที่ด้วยตัวคุณเองแม้ว่าสิ่งนี้มักจะเป็นปัญหาก็ตาม (ฉันคิดว่ามันจะเป็นในกรณีของคุณ)
และในที่สุดหากกรอบการแยกไม่ใช่ตัวเลือกและคุณมุ่งมั่นที่จะใช้แนวทางนี้ส่วนหน้าของ Joshua ที่กล่าวถึงเป็นแนวทางที่ดีหรือแนวทางใด ๆ โดยทั่วไปที่คุณแยกรหัสลูกค้าออกจากตรรกะทางธุรกิจที่คุณ กำลังใช้ในการทดสอบ
ฉันคิดว่าการเขียนผู้ให้บริการ app.config ของคุณเป็นงานง่ายๆและมีประโยชน์มากกว่าอย่างอื่น โดยเฉพาะอย่างยิ่งคุณควรหลีกเลี่ยงของปลอมเช่น shims เป็นต้นเพราะทันทีที่คุณใช้มัน 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; } }
}
แค่ตั้งค่าสิ่งที่คุณต้องการล่ะ? เพราะฉันไม่อยากล้อเลียน. NET ฉัน ... ?
System.Configuration.ConfigurationManager.AppSettings["myKey"] = "myVal";
คุณควรล้าง AppSettings ก่อนเพื่อให้แน่ใจว่าแอปเห็นเฉพาะสิ่งที่คุณต้องการ