Пересмешивающие события (основанный на событии асинхронный образец), используя Moq - как реагировать на событие в UT? - PullRequest
1 голос
/ 06 мая 2011

У меня есть служба, которая предоставляет асинхронную операцию через управляемый событиями асинхронный шаблон.

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 Ответ

6 голосов
/ 18 мая 2011

Трудно понять, что вы пытаетесь проверить здесь, поэтому я не могу дать вам 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);
}

Без дополнительной информации это лучшее, что я могу сделать. Я надеюсь, что это было то, что вы искали.

...