一个单元如何测试程序或基于事件的代码段

时间:2022-02-28 20:57:36

I'm convinced from this presentation and other commentary here on the site that I need to learn to Unit Test. I also realize that there have been many questions about what unit testing is here. Each time I go to consider how it should be done in the application I am currently working on, I walk away confused. It is a xulrunner application application, and a lot of the logic is event-based - when a user clicks here, this action takes place.

我从网站上的演示文稿和其他评论中确信我需要学习单元测试。我也意识到有很多关于单元测试的问题。每当我去考虑如何在我正在进行的应用程序中完成它时,我就会感到困惑。它是一个xulrunner应用程序,很多逻辑都是基于事件的 - 当用户点击此处时,会执行此操作。

Often the examples I see for testing are testing classes - they instantiate an object, give it mock data, then check the properties of the object afterward. That makes sense to me - but what about the non-object-oriented pieces?

我经常看到的测试示例是测试类 - 它们实例化一个对象,给它模拟数据,然后检查对象的属性。这对我来说很有意义 - 但是那些非面向对象的作品呢?

This guy mentioned that GUI-based unit testing is difficult in most any testing framework, maybe that's the problem. The presentation linked above mentions that each test should only touch one class, one method at a time. That seems to rule out what I'm trying to do.

这家伙提到基于GUI的单元测试在大多数测试框架中都很难,也许这就是问题所在。上面链接的演示文稿提到每个测试应该只触及一个类,一次一个方法。这似乎排除了我正在努力做的事情。

So the question - how does one unit testing procedural or event-based code? Provide a link to good documentation, or explain it yourself.

所以问题是 - 一个单元如何测试程序或基于事件的代码?提供良好文档的链接,或自行解释。

On a side note, I also have a challenge of not having found a testing framework that is set up to test xulrunner apps - it seems that the tools just aren't developed yet. I imagine this is more peripheral than my understanding the concepts, writing testable code, applying unit testing.

另外,我还面临着一个挑战,即没有找到一个测试框架来设置测试xulrunner应用程序 - 似乎这些工具还没有开发出来。我想这比我理解概念,编写可测试代码,应用单元测试更具外围性。

7 个解决方案

#1


5  

The idea of unit testing is to test small sections of code with each test. In an event based system, one form of unit testing you could do, would be to test how your event handlers respond to various events. So your unit test might set an aspect of your program into a specific state, then call the event listener method directly, and finally test the subsequent state of of your program.

单元测试的想法是测试每个测试的小部分代码。在基于事件的系统中,您可以执行的一种单元测试形式是测试事件处理程序如何响应各种事件。因此,您的单元测试可能会将程序的某个方面设置为特定状态,然后直接调用事件侦听器方法,最后测试程序的后续状态。

If you plan on unit testing an event-based system, you will make your life a lot easier for yourself if you use the dependency injection pattern and ideally would go the whole way and use inversion of control (see http://martinfowler.com/articles/injection.html and http://msdn.microsoft.com/en-us/library/aa973811.aspx for details of these patterns)

如果您计划对基于事件的系统进行单元测试,那么如果您使用依赖注入模式,那么您将使自己的生活变得更加轻松,理想情况下可以全面使用并使用控制反转(请参阅http://martinfowler.com /articles/injection.html和http://msdn.microsoft.com/en-us/library/aa973811.aspx了解这些模式的详细信息)

(thanks to pc1oad1etter for pointing out I'd messed up the links)

(感谢pc1oad1etter指出我搞砸了链接)

#2


2  

At first I would test events like this:

起初我会测试这样的事件:

private bool fired;

private void HandlesEvent(object sender, EventArgs e)
{
    fired = true;
 } 

public void Test()
{
   class.FireEvent += HandlesEvent;
   class.PErformEventFiringAction(null, null);

   Assert.IsTrue(fired);
}

And Then I discovered RhinoMocks. RhinoMocks is a framework that creates mock objects and it also handles event testing. It may come in handy for your procedural testing as well.

然后我发现了RhinoMocks。 RhinoMocks是一个创建模拟对象的框架,它还处理事件测试。它也可以用于您的程序测试。

#3


2  

Answering my own question here, but I came across an article that take explains the problem, and does a walk-through of a simple example -- Agile User Interface Development. The code and images are great, and here is a snippet that shows the idea:

在这里回答我自己的问题,但我遇到了一篇解释问题的文章,并做了一个简单的例子 - 敏捷用户界面开发。代码和图像都很棒,这里有一个显示这个想法的片段:

Agile gurus such as Kent Beck and David Astels suggest building the GUI by keeping the view objects very thin, and testing the layers "below the surface." This "smart object/thin view" model is analogous to the familiar document-view and client-server paradigms, but applies to the development of individual GUI elements. Separation of the content and presentation improves the design of the code, making it more modular and testable. Each component of the user interface is implemented as a smart object, containing the application behavior that should be tested, but no GUI presentation code. Each smart object has a corresponding thin view class containing only generic GUI behavior. With this design model, GUI building becomes amenable to TDD.

像Kent Beck和David Astels这样的敏捷大师建议通过保持视图对象非常薄来构建GUI,并测试“在表面下方”的图层。这种“智能对象/瘦视图”模型类似于熟悉的文档视图和客户端 - 服务器范例,但适用于单个GUI元素的开发。内容和表示的分离改进了代码的设计,使其更加模块化和可测试。用户界面的每个组件都实现为智能对象,包含应测试的应用程序行为,但不包含GUI表示代码。每个智能对象都有一个相应的瘦视图类,只包含通用的GUI行为。通过这种设计模型,GUI构建变得适合TDD。

#4


1  

The problem is that "event based programming" links far too much logic to the events. The way such a system should be designed is that there should be a subsystem that raises events (and you can write tests to ensure that these events are raised in the proper order). And there should be another subsystem that deals only with managing, say, the state of a form. And you can write a unit test that will verify that given the correct inputs (ie. events being raised), will set the form state to the correct values.

问题是“基于事件的编程”与事件的逻辑联系太多。应该设计这样一个系统的方式是应该有一个子系统来引发事件(你可以编写测试来确保以正确的顺序引发这些事件)。应该有另一个子系统只处理管理,比如表单的状态。您可以编写一个单元测试来验证给定正确的输入(即正在引发的事件),将表单状态设置为正确的值。

Beyond that, the actual event handler that is raised from component 1, and calls the behavior on component 2 is just integration testing which can be done manually by a QA person.

除此之外,从组件1引发并调用组件2上的行为的实际事件处理程序只是集成测试,可以由QA人员手动完成。

#5


1  

Your question doesn't state your programming language of choice, but mine is C# so I'll exemplify using that. This is however just a refinement over Gilligans answer by using anonymous delegates to inline your test code. I'm all in favor of making tests as readable as possible, and to me that means all test code within the test method;

你的问题没有说明你选择的编程语言,但我的是C#,所以我将使用它来举例说明。然而,这只是对Gilligans回答的改进,通过使用匿名代理来内联您的测试代码。我赞成尽可能让测试可读,对我来说,这意味着测试方法中的所有测试代码;

// Arrange
var car = new Car();
string changedPropertyName = "";
car.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
                        {
                           if (sender == car) 
                                  changedPropertyName = e.PropertyName;
                        };

// Act
car.Model = "Volvo";

// Assert 
Assert.AreEqual("Model", changedPropertyName, 
    "The notification of a property change was not fired correctly.");

The class I'm testing here implements the INotifyPropertyChanged interface and therefore a NotifyPropertyChanged event should be raised whenever a property's value has changed.

我在这里测试的类实现了INotifyPropertyChanged接口,因此每当属性值发生变化时都应该引发NotifyPropertyChanged事件。

#6


0  

An approach I've found helpful for procedural code is to use TextTest. It's not so much about unit testing, but it helps you do automated regression testing. The idea is that you have your application write a log then use texttest to compare the log before and after your changes.

我发现有助于过程代码的方法是使用TextTest。它不是单元测试,而是帮助您进行自动化回归测试。我们的想法是让您的应用程序编写日志,然后使用texttest比较更改前后的日志。

#7


0  

See the oft-linked Working Effectively with Legacy Code. See the sections titled "My Application Is All API Calls" and "My Project is Not Object-Oriented. How Do I Make Safe Changes?".

请参阅经常与遗留代码有效联系。请参阅标题为“我的应用程序是所有API调用”和“我的项目不是面向对象的部分。如何进行安全更改?”部分。

In C/C++ world (my experience) the best solution in practice is to use the linker "seam" and link against test doubles for all the functions called by the function under test. That way you don't change any of the legacy code, but you can still test it in isolation.

在C / C ++世界(我的经验)中,实践中的最佳解决方案是使用链接器“seam”并链接测试双精度,以便测试所使用的所有函数。这样您就不会更改任何遗留代码,但您仍然可以单独测试它。

#1


5  

The idea of unit testing is to test small sections of code with each test. In an event based system, one form of unit testing you could do, would be to test how your event handlers respond to various events. So your unit test might set an aspect of your program into a specific state, then call the event listener method directly, and finally test the subsequent state of of your program.

单元测试的想法是测试每个测试的小部分代码。在基于事件的系统中,您可以执行的一种单元测试形式是测试事件处理程序如何响应各种事件。因此,您的单元测试可能会将程序的某个方面设置为特定状态,然后直接调用事件侦听器方法,最后测试程序的后续状态。

If you plan on unit testing an event-based system, you will make your life a lot easier for yourself if you use the dependency injection pattern and ideally would go the whole way and use inversion of control (see http://martinfowler.com/articles/injection.html and http://msdn.microsoft.com/en-us/library/aa973811.aspx for details of these patterns)

如果您计划对基于事件的系统进行单元测试,那么如果您使用依赖注入模式,那么您将使自己的生活变得更加轻松,理想情况下可以全面使用并使用控制反转(请参阅http://martinfowler.com /articles/injection.html和http://msdn.microsoft.com/en-us/library/aa973811.aspx了解这些模式的详细信息)

(thanks to pc1oad1etter for pointing out I'd messed up the links)

(感谢pc1oad1etter指出我搞砸了链接)

#2


2  

At first I would test events like this:

起初我会测试这样的事件:

private bool fired;

private void HandlesEvent(object sender, EventArgs e)
{
    fired = true;
 } 

public void Test()
{
   class.FireEvent += HandlesEvent;
   class.PErformEventFiringAction(null, null);

   Assert.IsTrue(fired);
}

And Then I discovered RhinoMocks. RhinoMocks is a framework that creates mock objects and it also handles event testing. It may come in handy for your procedural testing as well.

然后我发现了RhinoMocks。 RhinoMocks是一个创建模拟对象的框架,它还处理事件测试。它也可以用于您的程序测试。

#3


2  

Answering my own question here, but I came across an article that take explains the problem, and does a walk-through of a simple example -- Agile User Interface Development. The code and images are great, and here is a snippet that shows the idea:

在这里回答我自己的问题,但我遇到了一篇解释问题的文章,并做了一个简单的例子 - 敏捷用户界面开发。代码和图像都很棒,这里有一个显示这个想法的片段:

Agile gurus such as Kent Beck and David Astels suggest building the GUI by keeping the view objects very thin, and testing the layers "below the surface." This "smart object/thin view" model is analogous to the familiar document-view and client-server paradigms, but applies to the development of individual GUI elements. Separation of the content and presentation improves the design of the code, making it more modular and testable. Each component of the user interface is implemented as a smart object, containing the application behavior that should be tested, but no GUI presentation code. Each smart object has a corresponding thin view class containing only generic GUI behavior. With this design model, GUI building becomes amenable to TDD.

像Kent Beck和David Astels这样的敏捷大师建议通过保持视图对象非常薄来构建GUI,并测试“在表面下方”的图层。这种“智能对象/瘦视图”模型类似于熟悉的文档视图和客户端 - 服务器范例,但适用于单个GUI元素的开发。内容和表示的分离改进了代码的设计,使其更加模块化和可测试。用户界面的每个组件都实现为智能对象,包含应测试的应用程序行为,但不包含GUI表示代码。每个智能对象都有一个相应的瘦视图类,只包含通用的GUI行为。通过这种设计模型,GUI构建变得适合TDD。

#4


1  

The problem is that "event based programming" links far too much logic to the events. The way such a system should be designed is that there should be a subsystem that raises events (and you can write tests to ensure that these events are raised in the proper order). And there should be another subsystem that deals only with managing, say, the state of a form. And you can write a unit test that will verify that given the correct inputs (ie. events being raised), will set the form state to the correct values.

问题是“基于事件的编程”与事件的逻辑联系太多。应该设计这样一个系统的方式是应该有一个子系统来引发事件(你可以编写测试来确保以正确的顺序引发这些事件)。应该有另一个子系统只处理管理,比如表单的状态。您可以编写一个单元测试来验证给定正确的输入(即正在引发的事件),将表单状态设置为正确的值。

Beyond that, the actual event handler that is raised from component 1, and calls the behavior on component 2 is just integration testing which can be done manually by a QA person.

除此之外,从组件1引发并调用组件2上的行为的实际事件处理程序只是集成测试,可以由QA人员手动完成。

#5


1  

Your question doesn't state your programming language of choice, but mine is C# so I'll exemplify using that. This is however just a refinement over Gilligans answer by using anonymous delegates to inline your test code. I'm all in favor of making tests as readable as possible, and to me that means all test code within the test method;

你的问题没有说明你选择的编程语言,但我的是C#,所以我将使用它来举例说明。然而,这只是对Gilligans回答的改进,通过使用匿名代理来内联您的测试代码。我赞成尽可能让测试可读,对我来说,这意味着测试方法中的所有测试代码;

// Arrange
var car = new Car();
string changedPropertyName = "";
car.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
                        {
                           if (sender == car) 
                                  changedPropertyName = e.PropertyName;
                        };

// Act
car.Model = "Volvo";

// Assert 
Assert.AreEqual("Model", changedPropertyName, 
    "The notification of a property change was not fired correctly.");

The class I'm testing here implements the INotifyPropertyChanged interface and therefore a NotifyPropertyChanged event should be raised whenever a property's value has changed.

我在这里测试的类实现了INotifyPropertyChanged接口,因此每当属性值发生变化时都应该引发NotifyPropertyChanged事件。

#6


0  

An approach I've found helpful for procedural code is to use TextTest. It's not so much about unit testing, but it helps you do automated regression testing. The idea is that you have your application write a log then use texttest to compare the log before and after your changes.

我发现有助于过程代码的方法是使用TextTest。它不是单元测试,而是帮助您进行自动化回归测试。我们的想法是让您的应用程序编写日志,然后使用texttest比较更改前后的日志。

#7


0  

See the oft-linked Working Effectively with Legacy Code. See the sections titled "My Application Is All API Calls" and "My Project is Not Object-Oriented. How Do I Make Safe Changes?".

请参阅经常与遗留代码有效联系。请参阅标题为“我的应用程序是所有API调用”和“我的项目不是面向对象的部分。如何进行安全更改?”部分。

In C/C++ world (my experience) the best solution in practice is to use the linker "seam" and link against test doubles for all the functions called by the function under test. That way you don't change any of the legacy code, but you can still test it in isolation.

在C / C ++世界(我的经验)中,实践中的最佳解决方案是使用链接器“seam”并链接测试双精度,以便测试所使用的所有函数。这样您就不会更改任何遗留代码,但您仍然可以单独测试它。