2010-03-23 30 views
2

更新:我改變了這個問題的措辭。以前,如果在運行時可以更改基類,那麼是/否問題。如何在C#中的單元測試時間模擬/僞造/替換/存根基類?

我可能在這裏不可能完成任務,但我似乎正在接近。我想擴展一個ASP.NET控件,並且我希望我的代碼是單元可測試的。另外,我希望能夠僞造真正Label的行爲(即ID生成等),這是真正的Label在nUnit主機中無法做到的。

這裏有一個工作示例,它對依賴於真實基類的東西進行斷言,而不是在更真實的單元測試中,測試將依賴於--i.e。存在的ID和一些自定義行爲。

總之代碼表示,它比我好的人:

public class LabelWrapper : Label //Runtime 
//public class LabelWrapper : FakeLabel //Unit Test time 
{ 
    private readonly LabelLogic logic= new LabelLogic(); 

    public override string Text 
    { 
     get 
     { 
      return logic.ProcessGetText(base.Text); 
     } 
     set 
     { 
      base.Text=logic.ProcessSetText(value); 
     } 
    } 
} 

//Ugh, now I have to test FakeLabelWrapper 
public class FakeLabelWrapper : FakeLabel //Unit Test time 
{ 
    private readonly LabelLogic logic= new LabelLogic(); 

    public override string Text 
    { 
     get 
     { 
      return logic.ProcessGetText(base.Text); 
     } 
     set 
     { 
      base.Text=logic.ProcessSetText(value); 
     } 
    } 
} 

[TestFixture] 
public class UnitTest 
{ 
    [Test] 
    public void Test() 
    { 
     //Wish this was LabelWrapper label = new LabelWrapper(new FakeBase()) 
     LabelWrapper label = new LabelWrapper(); 
     //FakeLabelWrapper label = new FakeLabelWrapper(); 
     label.Text = "ToUpper"; 
     Assert.AreEqual("TOUPPER",label.Text); 
     StringWriter stringWriter = new StringWriter(); 
     HtmlTextWriter writer = new HtmlTextWriter(stringWriter); 
     label.RenderControl(writer); 
     Assert.AreEqual(1,label.ID); 
     Assert.AreEqual("<span>TOUPPER</span>", stringWriter.ToString()); 
    } 
} 

public class FakeLabel 
{ 
    virtual public string Text { get; set; } 
    public void RenderControl(TextWriter writer) 
    { 
     writer.Write("<span>" + Text + "</span>"); 
    } 
} 

//System Under Test 
internal class LabelLogic 
{ 
    internal string ProcessGetText(string value) 
    { 
     return value.ToUpper(); 
    } 

    internal string ProcessSetText(string value) 
    { 
     return value.ToUpper(); 
    } 
} 

回答

3

這簡直是不可能的.NET。您無法即時更改已編譯的元數據。

想想這會造成的所有破壞。假裝我有以下情況

class Example { 
    Label l = new LabelWrapper(); 
} 

這些代碼執行,突然你的代碼運行切換的LabelWrapper基本類型是FakeLabel。這引起了許多非常多毛的問題,包括但不限於:

  • Example的現有實例會發生什麼情況?
  • Example的新實例會發生什麼情況,因爲此代碼現在完全無效?
  • 這引入了安全噩夢的數量,因爲我現在可以通過API無法解釋的方式實時改變我的對象。
+0

我同意你的看法,在運行時沒有辦法改變基類。我仍然希望找到模式來模擬它。但是,我不確定(如果可能的話),這與返回具有相同基類或支持相同接口的替代實現的工廠有什麼不同。工廠可能會選擇惡意實施或無效實施。 – MatthewMartin 2010-03-23 20:55:27

-1

我不太瞭解你的例子。但如果你想部分改變你的單元測試LabelWrapper的行爲,你可以使用Moq

Moq是一個Mocking框架,它允許在選定的方法上設置你的模擬特定的行爲。這意味着你會測試你的LabelWrapper的模擬版本,但這非常規。