gpt4 book ai didi

c# - 如何验证一个事件已经被模拟取消订阅

转载 作者:太空狗 更新时间:2023-10-29 23:23:15 27 4
gpt4 key购买 nike

起订量版本:3.1.416.3

我们发现了一个由未取消订阅的事件引起的错误。我正在尝试编写一个单元测试来验证该事件是否已取消订阅。是否可以使用 Mock<T>.Verify(expression) 来验证这一点?

我最初的想法是:

mockSource.Verify(s => s.DataChanged -= It.IsAny<DataChangedHandler>());

但显然

An expression tree may not contain an assignment operator

然后我试了一下

mockSource.VerifySet(s => s.DataChanged -= It.IsAny<DataChangedHandler>());

但这给了我

System.ArgumentException: Expression is not a property setter invocation.

我如何验证取消订阅已经发生?

如何使用事件

public class Foo
{
private ISource _source;

public Foo(ISource source)
{
_source = source;
}

public void DoCalculation()
{
_source.DataChanged += ProcessData;

var done = false;

while(!done)
{
if(/*something is wrong*/)
{
Abort();
return;
}
//all the things that happen
if(/*condition is met*/)
{
done = true;
}
}

_source.DataChanged -= ProcessData;
}

public void Abort()
{
_source.DataChanged -= ProcessData; //this line was added to fix the bug
//other cleanup
}

private void ProcessData(ISource)
{
//process the data
}
}

忽略代码的复杂性,我们正在处理来自外部硬件的信号。这实际上对算法有意义。

最佳答案

假设 ProcessData 做了一些有意义的事情,即以有意义/可观察的方式改变 SUT(被测系统)的状态,或者对事件参数起作用,只是在模拟并检查更改是否发生就足够了。

改变状态的例子:

....
public void ProcessData(ISource source)
{
source.Counter ++;
}

...
[Test]
.....

sut.DoWork();
var countBeforeEvent = source.Count;
mockSource.Raise(s => s.DataChanged += null, new DataChangedEventArgs(fooValue));
Assert.AreEqual(countBeforeEvent, source.Count);

当然,以上内容应该适用于您在 ProcessData 中的任何实现。

在进行单元测试时,您不应该关心实现细节(即是否取消订阅某些事件)并且不应该测试它,而应该关心行为 - 即如果您引发事件,是否会发生某些事情。在您的情况下,足以验证 ProcessData 未被调用。当然,您需要另一个测试来证明在正常操作(或某些条件)期间调用了该事件。

编辑:以上是使用最小起订量。但是……最小起订量是一种工具,与任何工具一样,它应该用于正确的工作。如果您真的需要测试“-=”是否被调用,那么您应该选择一个更好的工具——比如实现您自己的 ISource stub 。下面的示例有非常无用的被测类,它只是订阅然后取消订阅事件,只是为了演示如何测试。

using System;
using NUnit.Framework;
using SharpTestsEx;

namespace StackOverflowExample.Moq
{
public interface ISource
{
event Action<ISource> DataChanged;
int InvokationCount { get; set; }
}

public class ClassToTest
{
public void DoWork(ISource source)
{
source.DataChanged += this.EventHanler;
}

private void EventHanler(ISource source)
{
source.InvokationCount++;
source.DataChanged -= this.EventHanler;
}
}

[TestFixture]
public class EventUnsubscribeTests
{
private class TestEventSource :ISource
{
public event Action<ISource> DataChanged;
public int InvokationCount { get; set; }

public void InvokeEvent()
{
if (DataChanged != null)
{
DataChanged(this);
}
}

public bool IsEventDetached()
{
return DataChanged == null;
}
}

[Test]
public void DoWork_should_detach_from_event_after_first_invocation()
{
//arrange
var testSource = new TestEventSource();
var sut = new ClassToTest();
sut.DoWork(testSource);

//act
testSource.InvokeEvent();
testSource.InvokeEvent(); //call two times :)

//assert
testSource.InvokationCount.Should("have hooked the event").Be(1);
testSource.IsEventDetached().Should("have unhooked the event").Be.True();
}
}
}

关于c# - 如何验证一个事件已经被模拟取消订阅,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19023285/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com