Самое простое, что вы можете сделать, это подписать анонимный метод или лямбду на событие и увеличить счетчик, который является локальным для вашего теста в нем. Нет необходимости использовать дополнительный класс вообще.
Я обнаружил, что это не сделает ваш код очень читабельным, поэтому я сделал то же самое. Я написал объекты монитора в нескольких проектах. Обычно они немного более общие, чем ваш монитор. Они просто предоставляют открытые методы, на которые вы можете подписаться на события, и подсчитывают, сколько раз они были вызваны. Таким образом, вы можете повторно использовать объекты монитора для различных событий.
Примерно так:
MyObject subjectUnderTest = new MyObject();
EventMonitor monitor = new Monitor();
subjectUnderTest.Event += monitor.EventCatcher;
// testcode;
Assert.Equal( 1, monitor.EventsFired );
Проблема в том, что это не совсем универсально. Вы можете тестировать только те события, на которые monitor.EventCatcher () можно подписаться. Обычно я не делаю события с аргументами, так что это не проблема, у меня просто стандартный void EventCatcher (отправитель объекта, аргументы EventArgs). Вы можете сделать это более универсальным, подписав лямбду правильного типа на событие и вызвав EventCatcher в лямбде. Это делает ваши тесты немного сложнее для чтения. Вы также можете использовать универсальные шаблоны, чтобы метод EventCatcher работал с универсальным EventHandler.
Возможно, вы захотите посмотреть, в конце концов вы захотите хранить точно, какие события были вызваны, в каком порядке и с какими параметрами. Ваш монитор событий может легко выйти из-под контроля.
Я нашел другой способ сделать это, который мог бы иметь смысл для тестов с более сложными утверждениями.
Вместо того, чтобы создавать свой собственный монитор, вы позволяете создаваемой имитационной структуре создавать его для себя, вы просто создаете интерфейс для класса, который обрабатывает событие. Примерно так:
public interface IEventHandlerStub
{
event EventHandler<T> Event(object sender, T arguments);
}
Тогда вы можете смоделировать этот интерфейс в своем тесте. Rhino Mocks делает это так:
var eventHandlerStub = MockRepository.GenerateStub<IEventHandlerStub>();
myObject.Event += eventHandlerStub.Event;
// Run your code
eventHandlerStub.AssertWasCalled(x => x.Event(null, null));
Для такого простого теста это может быть излишним, но если вы хотите, например, утверждать что-то о параметрах, вы можете использовать для этого гибкость фреймворка.
На другой ноте . Мы с Робом работаем над общим классом монитора для тестирования событий, который может сделать некоторые из них более простыми. Если люди хотят использовать что-то подобное, я бы хотел услышать от вас.