Пересмешивающие события (основанный на событии асинхронный образец), используя Moq - как реагировать на событие в UT?
У меня есть сервис, который выставляет асинхронную операцию через управляемый событиями асинхронный шаблон.
public interface IService
{
void DoAsync(int param);
event DoCompleted;
}
Существует еще один класс, который зависит от объекта службы IService
public class Foo
{
private IService _service;
public EventHandler CalculationComplete;
public void Foo(IService service) {_service = service};
public int Calculated;
public void CalculateAsync(int param)
{
//Invoke _service.DoAsync(param)
//(...)
}
}
В основном после вызова foo.CalculateAsyc CalculationComplete должен уведомить потребителя о завершении калькуляции.
Вопрос в том, как издеваться над IService при юнит-тестировании Foo? Я использую Moq. Более конкретно, как заставить unittest ждать события CalculationComplete и реагировать соответственно?
1 ответ
Трудно понять, что вы пытаетесь проверить здесь, поэтому я не могу дать вам 100% точную выборку. В вашем примере кода, похоже, отсутствует довольно много деталей... Я заполнил некоторые из пропущенных битов, но есть еще вопросы.
В любом случае, метод, который я использую для ожидания событий, - это семафор. Мне нравится использовать AutoResetEvent для этого в простых случаях, как это.
public class Foo
{
private IService _service;
public EventHandler CalculationComplete;
public Foo(IService service)
{
_service = service;
_service.DoCompleted += (o,e) =>
{
Calculated = e.Result;
if(CalculationComplete != null) { CalculationComplete(this, new EventArgs()); }
};
}
public int Calculated;
public void CalculateAsync(int param)
{
_service.DoAsync(param);
}
}
public interface IService
{
void DoAsync(int param);
event EventHandler<DoResultEventArgs> DoCompleted;
}
public class DoResultEventArgs : EventArgs
{
public int Result { get; set; }
}
[TestMethod]
public void CalculateAsync_CallsService_CalculatedIsPopulated()
{
//Arrange
Mock<IService> sMock = new Mock<IService>();
sMock.Setup(s => s.DoAsync(It.IsAny<int>()))
.Raises(s => s.DoCompleted += null, new DoResultEventArgs() { Result = 324 });
Foo foo = new Foo(sMock.Object);
AutoResetEvent waitHandle = new AutoResetEvent(false);
foo.CalculationComplete += (o,e) => waitHandle.Set();
//Act
foo.CalculateAsync(12);
waitHandle.WaitOne();
//Assert
Assert.IsEqual(foo.Calculated, 324);
}
Без дополнительной информации это лучшее, что я могу сделать. Я надеюсь, что это было то, что вы искали.