代码之家  ›  专栏  ›  技术社区  ›  MakePeaceGreatAgain

为事件的add访问器编写单元测试

  •  0
  • MakePeaceGreatAgain  · 技术社区  · 7 年前

    我有一个从第三方程序集调用的方法,作为我们的应用程序入口点。这个方法引发了我们的事件 MyEvent add 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 -方法仅用于测试事件。

    1 回复  |  直到 7 年前
        1
  •  1
  •   MakePeaceGreatAgain    7 年前

    https://stackoverflow.com/a/12000050/2528063

    你必须知道,一件事只不过是一件小事 add -以及 remove -方法围绕私有(隐藏)委托字段,就像属性只是围绕私有(也隐藏)支持字段的get-and-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());
    

    当然,我们应该添加一些健全性检查,例如,对于代理被重命名的情况,因此找不到代理,但我想你明白了。