2012-02-01 88 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),那么您的代码将具有更好的可测试性。