使用反射在 C# 中引发事件的单元测试

Unit testing that an event is raised in C#, using reflection(使用反射在 C# 中引发事件的单元测试)
本文介绍了使用反射在 C# 中引发事件的单元测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想测试设置某个属性(或更一般地说,执行某些代码)是否会在我的对象上引发某个事件.在这方面,我的问题类似于 单元测试事件是在 C# 中提出,但我需要很多这样的测试,而且我讨厌样板.所以我正在寻找一个更通用的解决方案,使用反射.

I want to test that setting a certain property (or more generally, executing some code) raises a certain event on my object. In that respect my problem is similar to Unit testing that an event is raised in C#, but I need a lot of these tests and I hate boilerplate. So I'm looking for a more general solution, using reflection.

理想情况下,我想做这样的事情:

Ideally, I would like to do something like this:

[TestMethod]
public void TestWidth() {
    MyClass myObject = new MyClass();
    AssertRaisesEvent(() => { myObject.Width = 42; }, myObject, "WidthChanged");
}

对于 AssertRaisesEvent 的实现,我已经走到了这一步:

For the implementation of the AssertRaisesEvent, I've come this far:

private void AssertRaisesEvent(Action action, object obj, string eventName)
{
    EventInfo eventInfo = obj.GetType().GetEvent(eventName);
    int raisedCount = 0;
    Action incrementer = () => { ++raisedCount; };
    Delegate handler = /* what goes here? */;

    eventInfo.AddEventHandler(obj, handler);
    action.Invoke();
    eventInfo.RemoveEventHandler(obj, handler);

    Assert.AreEqual(1, raisedCount);
}

如您所见,我的问题在于为此事件创建一个适当类型的 Delegate.委托除了调用 incrementer 之外什么都不应该做.

As you can see, my problem lies in creating a Delegate of the appropriate type for this event. The delegate should do nothing except invoke incrementer.

由于 C# 中的所有语法糖浆,我对委托和事件如何真正工作的概念有点模糊.这也是我第一次涉足反思.缺少什么?

Because of all the syntactic syrup in C#, my notion of how delegates and events really work is a bit hazy. This is also the first time I dabble in reflection. What's the missing part?

推荐答案

我最近写了一系列关于发布同步和异步事件的对象的单元测试事件序列的博客文章.这些帖子描述了一种单元测试方法和框架,并提供了带有测试的完整源代码.

I recently wrote a series of blog posts on unit testing event sequences for objects that publish both synchronous and asynchronous events. The posts describe a unit testing approach and framework, and provides the full source code with tests.

我描述了一个事件监视器"的实现,它允许编写事件排序单元测试更简洁,即摆脱所有凌乱的样板代码.

I describe the implementation of an "event monitor" which allows writing event sequencing unit tests to be written more cleanly i.e. getting rid of all the messy boilerplate code.

使用我的文章中描述的事件监视器,可以这样编写测试:

Using the event monitor described in my article, tests can be written like so:

var publisher = new AsyncEventPublisher();

Action test = () =>
{
    publisher.RaiseA();
    publisher.RaiseB();
    publisher.RaiseC();
};

var expectedSequence = new[] { "EventA", "EventB", "EventC" };

EventMonitor.Assert(publisher, test, expectedSequence);

或者对于实现 INotifyPropertyChanged 的​​类型:

Or for a type that implements INotifyPropertyChanged:

var publisher = new PropertyChangedEventPublisher();

Action test = () =>
{
    publisher.X = 1;
    publisher.Y = 2;
};

var expectedSequence = new[] { "X", "Y" };

EventMonitor.Assert(publisher, test, expectedSequence);

对于原始问题中的情况:

And for the case in the original question:

MyClass myObject = new MyClass();
EventMonitor.Assert(myObject, () => { myObject.Width = 42; }, "Width");

EventMonitor 完成所有繁重的工作,并将运行测试(操作)并断言事件以预期的顺序(expectedSequence)引发.它还会在测试失败时打印出很好的诊断消息.反射和 IL 用于在底层实现动态事件订阅,但这一切都被很好地封装了,所以只需要像上面这样的代码来编写事件测试.

The EventMonitor does all the heavy lifting and will run the test (action) and assert that events are raised in the expected sequence (expectedSequence). It also prints out nice diagnostic messages on test failure. Reflection and IL are used under the hood to get the dynamic event subscription working, but this is all nicely encapsulated, so only code like the above is required to write event tests.

在描述问题和方法的帖子中有很多细节,还有源代码:

There's a lot of detail in the posts describing the issues and approaches, and source code too:

http://gojisoft.com/blog/2010/04/22/event-sequence-unit-testing-part-1/

这篇关于使用反射在 C# 中引发事件的单元测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

DispatcherQueue null when trying to update Ui property in ViewModel(尝试更新ViewModel中的Ui属性时DispatcherQueue为空)
Drawing over all windows on multiple monitors(在多个监视器上绘制所有窗口)
Programmatically show the desktop(以编程方式显示桌面)
c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
LINQ many-to-many relationship, how to write a correct WHERE clause?(LINQ多对多关系,如何写一个正确的WHERE子句?)