c# - 为事件的添加访问器编写单元测试
问题描述
我有一个从第 3 方程序集调用的方法,用作我们的应用程序入口点。这个方法引发了我们的事件MyEvent
。为了确保相同的事件处理程序只注册一次且仅一次,我实现了自己的add
and逻辑remove
:
class MyEditorExtension
{
private EventHandler<MyArgs> myEvent
public EventHandler<MyArgs> MyEvent
{
add
{
if(this.myEvent == null || this.myEvent.GetInvocationList().All(x => !x.Equals(value))
this.myEvent += value;
}
remove { this.myEvent -= value; }
}
// this method is called from ArcMap
public void OnCreate()
{
...
MyEvent();
}
}
OnCreate
非常庞大,不能安全地重构为更小的、可测试的单元。但是我想检查我的事件定义是否真的做了它应该做的事情。为了做到这一点,我尝试两次注册完全相同的方法并检查它是否被执行了两次:
[TestFixture]
public class ExtensionTest
{
int numCalls;
[Test]
public void Test_Register_Handler_Twice()
{
var target = new MyExtension();
target.MyEvent += myHandler;
target.MyEvent += myHandler;
target.MyEvent(new MyArgs());
Assert.AreEqual(1, this.numCalls);
}
private void(MyArgs args) { this.numCalls ++; }
}
当然,以上内容不会编译,因为我无法在其类之外引发事件。我还想避免RaiseEvent
仅仅为了测试事件而引入 -method。
所以我想知道是否有任何方法可以实现这一点,例如使用反射?
解决方案
实际上,可以使用反射。然而,这很hacky。事实上,在测试遗留代码时,这是一个常见问题。这个解决方案的灵感来自这篇文章:https ://stackoverflow.com/a/12000050/2528063
你必须知道,一个事件只不过是一个围绕私有(隐藏)委托字段的add
- 和remove
- 方法,就像一个属性只不过是一个围绕私有(也是隐藏)支持字段的 get 和 set 方法一样。话虽如此,您可以访问该委托,该委托通常与您的事件具有完全相同的名称:
var delegateField = typeof(MyExtension).GetField("MyEvent", BindingFlags.NonPublic)?.GetValue(target);
在我们的特殊情况下,我们有自己的访问器,因此委托的名称直接在源 cde 中提供MyExtension
。因此,我们编写了这个略有不同的版本:
var delegateField = typeof(MyExtension).GetField("myEvent", BindingFlags.NonPublic)?.GetValue(target);
现在我们有了支持委托,我们可以轻松调用它:
delegateField?.DynamicInvoke(new MyArgs());
当然,我们应该添加一些完整性检查,例如对于委托被重命名因此无法找到的情况,但我想你明白了。
推荐阅读
- matlab - 在 MATLAB 中查找雅可比模式以指定“jpattern”
- php - 在 Laravel ajax 中的表中搜索后如何从 1 重新开始列号?
- php - 为 Laravel API 存储数据时没有任何反应
- ios - 开发者和帐户持有人都需要付费的 Apple Developer 帐户吗?
- javascript - 如何使用 Javascript 过滤多个数组
- android - 如果用户不先点击 Firebase 身份验证发送的验证链接,如何防止用户登录 Android 应用?
- java - 尝试将 JavaEE 应用程序连接到数据库服务器时出现 DBException
- http - 对于给定的 CDN 图片 url,浏览器如何连接到最近的 CDN 服务器?
- spring - Spring Batch - 元表 - Oracle 12C - UTC 时区条目
- excel - ExcelVBA:SaveCopyAs 不允许编辑新工作簿