unit testingWindows窗体应用程序的建议

我已经编写了一个Windows窗体应用程序,现在我想为它编写一些unit testing(不完全是测试驱动的开发,因为我在开发后编写测试但是迟到的时候从未好过!)我的问题是这样的应用程序你如何编写unit testing,因为几乎所有的方法和事件都是私有的? 我听说过NUnit Forms,但是我听到了它的优点和缺点,而且该项目暂时没有真正的发展,所以它看起来已经废弃了。 此外,如果我为用户通过点击/按下按钮触发的所有事件编写unit testing用例,或者我必须为所有人编写unit testing用例,那么该项目已经进行了足够的unit testing方法并找出一种方法来测试我的私有方法?

编辑:我的业务逻辑与我的表示逻辑分离,我的业务逻辑公开了1或2个公共方法,因此表单可以访问它们,但是业务逻辑中的所有私有方法呢?

我要做的第一件事是确保您的业务逻辑与表单正确分离。 基本上,使用MVC模式。 然后,您可以轻松地测试表单外的所有内容,就好像表单甚至不存在一样。

现在,这仍然可能会留下一些未经测试的特定于表单的function。 IE,是否正确连接到服务的表单? 为此,您仍然可以考虑NUnit Forms或其他替代方案。

unit testing图形应用程序的关键是确保所有业务逻辑都在一个单独的类中,而不是在后面的代码中。

设计此类系统时, 模型视图展示器和模型视图控制器等设计模式可以提供帮助。

举个例子:

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"; } } 

正如您所看到的,Form只有一些基础设施代码可以将您的所有内容组合在一起。 您的所有逻辑都在Presenter类中,它只知道View Interface。

如果你想对它进行unit testing,你可以使用像Rhino Mocks这样的模拟工具来模拟View界面并将其传递给你的演示者。

 [TestMethod] public void TestChangeData() { IMyView view = MockRepository.DynamickMock(); view.Stub(v => v.SomeData).PropertyBehavior(); MyPresenter presenter = new MyPresenter(view); presenter.ChangeData(); Assert.AreEqual("Some changed data", view.SomeData); } 

你有几个选择。

  1. 使用Coded UI等工具通过您的用户界面进行测试。 这不是一个很好的选择,因为它比unit testing慢,而且测试往往更脆弱。

  2. 将业务逻辑与表示逻辑分开。 如果您的UI中有许多私有方法执行业务逻辑,那么您的业务逻辑与您的演示文稿紧密相关。 开始识别这些并将它们移出到可以测试的公共接口的单独类。 阅读SOLID原则,它可以帮助您保持代码松散耦合和可测试。

将所有业务逻辑分解为单独的项目和unit testing。 或者至少将表单中的所有逻辑移动到单独的类中。

使用审批测试(www.approvaltests.com或nuget)对View进行unit testing非常简单。 这里有一个video: http : //www.youtube.com/watch?v = hKeKBjoSfJ8

但是,为了能够测试function,您似乎还担心将函数设置为默认值或公共函数。

这些通常被称为接缝; 进入测试代码的方法。 而且他们很好。 有时候人们会把私人/公众与安全混为一谈,并且害怕将私人function公之于众,但是反思也会调用,所以它并不是真的安全。 其他时候人们担心类的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) 

更容易测试相应的鼠标单击事件,并且直通调用仍然可以是单个可忽略的行。

可以使用带有Reactive.UI的MVVM(Model-View-ViewModel)模式来创建可测试的WinForms代码。 要真正需要分离关注点。 请参阅:Reactive.UI https://reactiveui.net/使用Winforms / MVVM / Reactive.UI的主要缺点是没有很多使用它的示例(对于WinForms)。 好处是它几乎适用于所有桌面框架和语言。 你可以学习它,但这些原则适用于所有人。 当你有很多私人方法时,那没关系。 恕我直言:尝试使用公共方法来开始您想要测试的业务流程。 您可以使用tell-not-ask: https : //martinfowler.com/bliki/TellDontAsk.html并仍将所有这些方法保密。

也可以通过驱动UI来测试代码,但这不是强烈推荐的,因为结果测试是(1)非常脆弱,(2)难以工作,并且恕我直言,(3)不能写在与纯代码测试相同的细粒度; (4)最后:如果您使用数据库,则需要考虑使用测试数据填充它,并且,因为在每次测试之前您的数据库必须处于干净,定义良好的状态,(5)您的测试可能运行得更慢而不是你想重新初始化每个测试的数据。

简介:使用良好的SoC编写代码(例如,通过应用MVVM),那么您的代码将具有更好的可测试性。