2012-02-01 65 views
17

我寫了一個Windows窗體應用程序,現在我想爲它編寫一些單元測試(不完全是測試驅動的開發,因爲我在開發之後編寫測試,從來沒有!)我的問題是,用這樣的應用程序,你怎麼去編寫單元測試,因爲幾乎所有的方法和事件都是私有的?我聽說過NUnit Forms,但我聽到了好消息和壞消息,一段時間以來,這個項目一直沒有真正的發展,所以看起來很遺憾。同樣,如果我爲所有用戶通過點擊/按下按鈕觸發的事件編寫單元測試用例,或者我必須爲所有用戶編寫單元測試用例方法並找出一種方法來測試我的私有方法?單元測試Windows窗體應用程序的建議

編輯:我的商業邏輯是從我的表現邏輯分隔,有1種或2個公共方法我的業務邏輯自曝這樣的形式可以訪問它們,但對於所有的私有方法,這些方法在商業邏輯?

回答

14

我會做的第一件事是確保您的業務邏輯與表單恰當分離。基本上,使用MVC模式。然後,您可以輕鬆地測試表單外的所有內容,就好像表單不存在一樣。

現在,這仍然可能會留下一些未經測試的特定於表單的功能。 I.E.,是否正確連接到服務的形式?爲此,您仍然可以考慮像NUnit Forms或其他替代方法。

+0

OK我有,但是如果我有我的形式訪問我的商業邏輯1種或2的公共方法,並在我的業務邏輯,並依次訪問私有方法,它足以給公衆接口測試,以我的形式業務邏輯?而不是寫單元測試直接測試我的私有方法? – DukeOfMarmalade 2012-02-01 14:39:23

+0

@Jim - 是的,這被認爲是可以接受的我的很多,因爲測試的公共方法是行使私有方法中的代碼。 (這真的不會比移除私有方法和公有方法內的代碼轉移到內部的塊太大的不同。) – ziesemer 2012-02-01 14:43:48

+0

同意了!謝謝! – DukeOfMarmalade 2012-02-01 14:57:20

4

將所有業務邏輯分解爲單獨的項目和單元測試。或者至少將表單中的所有邏輯移入單獨的類。

5

您有幾個選項。

  1. 使用像編碼UI這樣的工具通過用戶界面進行測試。這不是一個好的選擇,因爲它比單元測試慢,而且測試往往更加脆弱。

  2. 將業務邏輯從您的表示邏輯中分離出來。如果您有很多在您的用戶界面中執行業務邏輯的私有方法,那麼您已將業務邏輯與演示文稿緊密結合。開始識別這些並將它們移出到具有您可以測試的公共接口的獨立類中。閱讀SOLID原理,它可以幫助你保持你的代碼鬆耦合和可測試性。

+0

至於#1:它不僅是不是一個很好的選擇,因爲它是緩慢的,這還不算,連單元測試。 UI測試就是這樣,它更接近集成測試。至於#2:不僅如果你有很多的私有方法,但是如果你有任何私有方法執行業務邏輯,你加入了你的代碼。耦合是耦合的,不應該有一個規模。除此之外,#2是完全正確的。 – Suamere 2015-01-10 20:43:23

25

單元測試圖形應用程序的關鍵是確保所有大多數業務邏輯都在單獨的類中,而不是在後面的代碼中。

設計模式如Model View PresenterModel View Controller可以幫助設計這樣一個系統。

舉個例子:

public partial class Form1 : Form, IMyView 
{ 
    MyPresenter Presenter; 
    public Form1() 
    { 
     InitializeComponent(); 
     Presenter = new MyPresenter(this); 
    } 

    public string SomeData 
    { 
     get 
     { 
      throw new NotImplementedException(); 
     } 
     set 
     { 
      MyTextBox.Text = value; 
     } 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     Presenter.ChangeData(); 
    } 
} 

public interface IMyView 
{ 
    string SomeData { get; set; } 
} 

public class MyPresenter 
{ 
    private IMyView View { get; set; } 
    public MyPresenter(IMyView view) 
    { 
     View = view; 
     View.SomeData = "test string"; 
    } 

    public void ChangeData() 
    { 
     View.SomeData = "Some changed data"; 
    } 
} 

正如你可以看到,該表格只有一些基礎的代碼到你的一切融合在一起。你所有的邏輯都在你的Presenter類中,它只知道View接口。

如果你想單元測試這個,你可以使用一個模擬工具,如Rhino Mocks來模擬View界面並將其傳遞給演示者。

[TestMethod] 
public void TestChangeData() 
{ 
    IMyView view = MockRepository.DynamickMock<IMyView>(); 
    view.Stub(v => v.SomeData).PropertyBehavior(); 

    MyPresenter presenter = new MyPresenter(view); 

    presenter.ChangeData(); 

    Assert.AreEqual("Some changed data", view.SomeData); 
} 
0

使用驗證測​​試(www.approvaltests.com或nuget)對View進行測試的單元足夠簡單。這裏有一個視頻:http://www.youtube.com/watch?v=hKeKBjoSfJ8

但是,它似乎也是你擔心爲了能夠測試功能的目的而默認或公開一個函數。

這些通常被稱爲接縫;進入你的代碼進行測試的方法。 他們很好。有時候,人們會將私人/公衆與安全混爲一談,並且不敢公開私人職能,但反思也會稱之爲安全,所以它不是很安全。有時候人們會擔心API的接口。但是,如果你有一個公共的API,並且如果你有一個winform應用程序,這可能意味着它是最高級別的(沒有其他消費者會這麼稱呼它)。

你是程序員,因此可以設計你的代碼以便於測試。這通常意味着比改變一些方法的公共和創建一些connivence方法,使依賴關係在傳遞多一點

例如:

buttonclick += (o,e)=> {/*somecode*/}; 

是很難測試。

private void button1_Click(object sender, EventArgs e) {/*somecode*/} 

仍難以測試

public void button1_Click(object sender, EventArgs e) {/*somecode*/} 

更容易測試

private void button1_Click(object sender, EventArgs e) { DoSave();} 
public void DoSave(){/*somecode*/} 

真的很容易測試!

如果您需要事件中的某些信息,這會增加一倍。即。

public void ZoomInto(int x, int y) 

更容易測試對應的鼠標點擊事件,並直通電話仍然可以是一個可忽略的線。

+1

有些人混淆理由,爲什麼壞的理由可能會忽略不計,有理由做正確的事情。封裝不僅僅是安全性。現在,編碼人員認爲,將未來的封裝成員公之於衆是他們失去了關注點和可靠的開發實踐的時候。現在,您的應用程序可能不會失去安全性,但不易維護,並採用變通方法進行測試,而不僅僅是正確執行。 – Suamere 2014-10-07 13:39:27

+0

民營上市後的事情是難以維持的時候...... 我常常在想如何將適用於所有不具有公共/私有如Ruby/JavaScript的/等語言... – 2015-01-08 18:40:52

+1

在選擇語言,您考慮的不僅僅是可以運行的硬件,還有代碼庫維護人員的優勢。您還考慮了該語言的優勢。 C#的主要優勢包括是類型安全,垃圾回收,通用的,友好的本地人結構,等等等等,只是因爲另一種語言(有自己的長處)不符合有關C#所做的評論並不意味着評論是相關的。 Javascript的主要優點是它不是類型安全的。這對解決的問題是最好的。另外,你可以在javascript中擁有私人成員。 – Suamere 2015-01-10 20:35:16

0

可以使用帶有Reactive.UI的MVVM(Model-View-ViewModel)模式來編寫可測試的WinForms代碼。真正需要分離問題。請參閱:Reactive.UI https://reactiveui.net/使用Winforms/MVVM/Reactive.UI的主要缺點是沒有太多使用它的例子(對於WinForms)。好處是它適用於幾乎所有的桌面框架和語言。你可以從中學到一點,但這些原則適用於所有人。當你有很多私人方法時,沒關係。恕我直言:嘗試使用公共方法開始您想要測試的業務流程。您可以使用tell-don't-ask:https://martinfowler.com/bliki/TellDontAsk.html並仍然保留所有這些方法爲私有。

也可以通過驅動用戶界面來測試代碼,但這並不是強烈推薦,因爲所得測試(1)非常脆弱,(2)難以工作,恕我直言,(3)不能寫在與純代碼測試相同的精細粒度水平上; (4)最後:如果你使用數據庫,你需要考慮用測試數據填充數據庫,並且,因爲你的數據庫在每次測試之前必須處於乾淨的,明確定義的狀態,(5)你的測試可能運行得更慢當您重新初始化每個測試的數據時,您的想法超出您的想象。簡介:使用良好的SoC編寫代碼(例如應用MVVM),那麼您的代碼將具有更好的可測試性。