如何运行分配给模拟的事件处理程序?
我正在尝试触发分配给我的计时器模拟的事件处理程序。我如何在这里测试这个私有方法?
public interface ITimer
{
void Start();
double Interval { get; set; }
event ElapsedEventHandler Elapsed;
}
客户端类为该对象分配一个事件处理程序。我想测试这门课的逻辑。
_timer.Elapsed += ResetExpiredCounters;
并且分配的方法是私有的,
private void ResetExpiredCounters(object sender, ElapsedEventArgs e)
{
// do something
}
我想在我的模拟中拥有这个事件处理程序并以某种方式运行它。我该怎么做?
更新:
我意识到在分配事件处理程序之前我正在引发该事件。我纠正了这一点,但我仍然收到此错误:
System.ArgumentException : Object of type 'System.EventArgs' cannot be converted
to type 'System.Timers.ElapsedEventArgs'.
我像这样提出它:
_timer.Raise(item => item.Elapsed += null, ElapsedEventArgs.Empty);
或者
_timer.Raise(item => item.Elapsed += null, EventArgs.Empty);
两者都不起作用。
更新:
这是对我有用的东西。请注意,如果您尝试将信息传递给事件处理程序(如乔恩在评论中指出的那样),则它没有用。我只是用它来模拟 System.Timers.Timer 类的包装器。
_timer.Raise(item => item.Elapsed += null, new EventArgs() as ElapsedEventArgs);
最后,如果您需要使用事件参数,这根本没有帮助,因为它始终为空。然而,这是唯一的方法,因为 ElapsedEventArgs 只有一个内部构造函数。
I am trying to fire the event handler assigned to my timer mock. How can I test this private method here?
public interface ITimer
{
void Start();
double Interval { get; set; }
event ElapsedEventHandler Elapsed;
}
Client class assigns an event handler to this object. I want to test the logic in this class.
_timer.Elapsed += ResetExpiredCounters;
And the assigned method is private
private void ResetExpiredCounters(object sender, ElapsedEventArgs e)
{
// do something
}
I want to have this event handler in my mock and run it somehow. How can I do this?
Update:
I realized I was raising the event before I assigned the event handler. I corrected that but I still get this error:
System.ArgumentException : Object of type 'System.EventArgs' cannot be converted
to type 'System.Timers.ElapsedEventArgs'.
I raise it like this:
_timer.Raise(item => item.Elapsed += null, ElapsedEventArgs.Empty);
or
_timer.Raise(item => item.Elapsed += null, EventArgs.Empty);
Both won't work.
Update:
Here's the thing that worked for me. Note that it's not useful if you are trying to pass info to event handler like Jon pointed out in comments. I am just using it to mock the wrapper for System.Timers.Timer class.
_timer.Raise(item => item.Elapsed += null, new EventArgs() as ElapsedEventArgs);
In the end, this won't help at all if you need to use event arguments since it will be always null. However, it's the only way since ElapsedEventArgs has only an internal constructor.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
ElapsedEventArgs
有一个私有构造函数,无法实例化。如果您使用:
那么处理程序将接收一个 null 参数并丢失其
SignalTime
属性:在某些情况下您可能需要此参数。
为了解决这个问题并使其更具可测试性,我还为
ElapsedEventArgs
创建了一个包装器,并让接口使用它:该实现将简单地触发其自己的事件,从实时计时器事件中获取数据:
现在,您可以简化和改进此事件的模拟:
编写的代码更少,更易于使用并且与框架完全解耦。
ElapsedEventArgs
has a private constructor and can not be instantiated.If you use:
Then the handler will recevie a null parameter and lose its
SignalTime
property:You might want this parameter in some cases.
To solve this and make it more testable, I also created a wrapper for the
ElapsedEventArgs
, and made the interface use it:The implementation will simply fire its own event getting the data from the real timer event:
Now, you can simplify and improve the mock of this event:
Less code to write, easier to work with and completely decoupled from the framework.
Moq 快速入门指南中有一个有关事件的部分。我想你会用
The Moq QuickStart guide has a section on events. I think you'd use
最近处理这个问题,您可以使用反射构造一个 ElapsedEventArgs:
这样您可以继续使用原始的 ElapsedEventHandler 委托
Dealt with this recently, you can construct an ElapsedEventArgs using reflection:
This way you can continue using the original ElapsedEventHandler delegate
OP 指出,他们可以简单地使用 new EventArgs() as ElapsedEventArgs ,这是一种很好的简单方法,可以在一行中完成它,并且假设该对象从未在处理程序中被检查,它将起作用 -但它将生成一个“可能的空引用”构建警告。
如果您的目标是零构建警告,那么此用例的最佳方法是避免 Yoyo 答案中过时的类,如下所示:
The OP points out that they can simply use
new EventArgs() as ElapsedEventArgs
which is a nice simple way to get it done in one line, and assuming the object is never examined in the handler it will work - but it will generate a "possible null reference" build warning.If you're aiming for zero build warnings then the best method for this use case, avoiding the obsolete classes in Yoyo's answer, is something like this:
可以做这样的事情来包装你的计时器
Could do something like this to wrap your
Timer