测试事件相关活动
测试事件监听者
- 检查监听对象是否对发生的事件做出某种响应。
- 如果监听者没有注册到这个事件,那它就不会采取任何可观察到的公共行为。
测试一个触发事件
事件相关代码
public class Presenter
{
private readonly IView _view;
public Presenter(IView view)
{
_view = view;
//在触发事件后调用OnLoaded方法
this._view.Loaded += OnLoaded;
}
private void OnLoaded()
{
_view.Render("Hello World");
}
}
还有一个接口
public interface IView
{
event Action Loaded;
event Action<string> ErrorOccured;
void Render(string text);
}
测试事件触发
- 这个模拟对象同时也是存根(桩)
- 要触发这个事件,在测试时就要注册这个事件
[Test]
public void ctor_WhenViewIsLoaded_CallsViewRender()
{
var mockView = Substitute.For<IView>();
Presenter p = new Presenter(mockView);
//使用NSubstitute触发事件
mockView.Loaded += Raise.Event<Action>();
//验证测试中是否调用了view的Render方法
mockView.Received().Render(Arg.Is<string>(s => s.Contains("Hello World")));
}
测试有两个依赖的事件
被测代码
//有两个依赖,一个日志和一个视图
class Presenter2
{
private readonly IView _view;
private readonly ILogger _log;
public Presenter2(IView view, ILogger log)
{
_view = view;
_log = log;
//发生Loaded事件时,调用OnLoaded
this._view.Loaded += OnLoaded;
//发生ErrorOccured事件时,调用OnError()方法,接收一个text
this._view.ErrorOccured += OnError;
}
private void OnError(string text)
{
_log.LogError(text);
}
private void OnLoaded()
{
_view.Render("Hello World");
}
}
测试模拟一个日志对象和一个视图
//模拟一个日志对象和一个视图
[Test]
public void ctor_WhenViewHasError_CallsLogger()
{
var stubView = Substitute.For<IView>();
var mockLogger = Substitute.For<ILogger>();
Presenter2 p = new Presenter2(stubView, mockLogger);
//1. 桩触发错误事件,由于OnError方法需要一个string所以事件要带一个参数
stubView.ErrorOccured += Raise.Event<Action<string>>("fake error");
//2. 使用模拟对象检查日志调用
mockLogger.Received().LogError(Arg.Is<string>(s => s.Contains("fake error")));
}
测试事件是否触发
比较简单的方法是:在测试方法内部使用一个匿名委托,手工注册这个方法。下面是伪代码。
//测试事件是否触发
//比较简单的方法是:在测试方法内部使用一个匿名委托,手工注册这个方法。下面是伪代码。
[Test]
public void EventFiringManual()
{
bool loadFired = false;
SomeView view = new SomeView();
//这个委托只记录这个事件是否触发
view.Load += Delegate
{
loadFired = true;
};
view.DoSomethingThatEventuallyFiresThisEvent();
Assert.IsTrue(loadFired);
}