通用事件测试方法,防止代码重复

时间:2017-10-20 15:28:45

标签: c# unit-testing events lambda

我试图创建一个测试套件来测试包含某个事件的类。基本上我希望调用一个方法,给该方法一个事件,一段测试代码和一个事件执行的对象,最后是事件被引发的预期次数。

我的第一次迭代是:

    protected void EventFireTest<T>(EventHandler theEvent, T g, TestAction<T> action) where T: class{
        var invokeChangedCount = 0;

        theEvent += (sender, e) => { ++invokeChangedCount; };            

        foreach (var actionPair in action.AllActions) {
            invokeChangedCount = 0;
            var num = actionPair.Item2;
            var actualAction = actionPair.Item1;
            actualAction(g);

            Assert.That(actual: invokeChangedCount, expression: Is.EqualTo(expected: num));

        }
    }

它会被称为:

EventFireTest(obj.PropertyChanged,obj,action);

其中action包含动作对以及一些元数据,例如正在执行的动作的视觉线索。

但是,当我尝试将事件传递给此函数时,问题是“事件只能是+ =和 - =”的lhs。即使这是我最终对事件做的唯一事情。 (编译器应该能够在理论上检查这个吗?)

现在为了避免这个问题,我采取了更加臃肿的方法,直接引入已经不需要的代码重复以及将内部细节放到外部测试方法中。通过为EventFireTest方法提供lambda来执行。

    protected void EventFireTest<T>(Action<int> EventSetupAction, T g, TestAction<T> action) where T: class{
        var invokeChangedCount = 0;

        EventSetupAction(invokeChangedCount);

        foreach (var actionPair in action.AllActions) {
            invokeChangedCount = 0;
            var num = actionPair.Item2;
            var actualAction = actionPair.Item1;
            actualAction(g);

            Assert.That(actual: invokeChangedCount, expression: Is.EqualTo(expected: num));

        }
    }

现在代码将被称为:

        Action<int> setup = n => obj.PropertyChanged += (sender, e) => {
            ++n;
        };
        EventFireTest(setup, obj, action);

我认为丑陋已经非常明显(突然间我需要关心如何计算事件的执行次数)。但更重要的是,上面的代码将不起作用。

而不是“更改”EventFireTest中的变量,lambda创建变量的本地副本,并更新它。所以我需要通过引用传递整数,如果没有一些复杂的方法,这也是不可能的。

这些问题使我相信我目前无法解决这个问题。大多数人都有更简单的方法吗?

1 个答案:

答案 0 :(得分:-1)

不是让你的委托取一个整数并增加它,而是让委托提供一个事件处理程序,并让委托的主体将该事件处理程序添加到事件中。这使调用者:

Action<EventHandler> setup = handler => obj.PropertyChanged += handler;
EventFireTest(setup, obj, action);

对于测试方法,您现在只需要将原始修订版中编写的处理程序作为参数传递给该操作。

解决问题的另一种方法是将T约束为实现某个接口的类型,其中接口定义了您需要订阅的事件。这只适用于此测试的所有调用者在逻辑上测试特定类型的事件而不是某些任意事件的情况。您的代码看起来更像后者,因此看起来并不适合您的情况。