Каков наилучший способ для unit test асинхронного метода?

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

Очевидно, мне нужно вызвать метод, а затем посмотреть, срабатывает ли обратный вызов, но есть ли лучший способ, чем просто спящий бит, а затем проверка флага, установленного обратным вызовом? Управление флагами становится немного грязным, когда выполняется несколько тестов.

Ответы

Ответ 1

Обычно я использую анонимный делегат и waithandle. Например, у меня есть функция в моем презентаторе, называемая SetRemoteTableName. Когда имя установлено, оно также вызывает событие. Я хочу проверить это событие, которое возникает асинхронно. Тест выглядит следующим образом:

[TestMethod]
[WorkItem(244)]
[Description("Ensures calling SetRemoteTableName with a valid name works 
              AND raises the RemoteTableNameChange event")]
public void SetRemoteTableNamePositive()
{
  string expected = "TestRemoteTableName";
  string actual = string.Empty;

  AutoResetEvent are = new AutoResetEvent(false);
  SQLCECollectorPresenter presenter = new SQLCECollectorPresenter();
  presenter.RemoteTableNameChange += new EventHandler<GenericEventArg<string>>(
    delegate(object o, GenericEventArg<string> a)
    {
      actual = a.Value;
      are.Set();
    });

  presenter.SetRemoteTableName(expected);
  Assert.IsTrue(are.WaitOne(1000, false), "Event never fired");
  Assert.AreEqual(actual, expected);
}

Ответ 2

Разделите код так, чтобы логика находилась в синхронном бите кода, который вызывается тонкой асинхронной оболочкой.

Тогда большинство ваших модульных тестов могут протестировать синхронный код.

Ответ 3

Есть ли лучший способ, чем просто спать немного, а затем проверить флаг, установленный обратным вызовом?

Замените флаг дескриптором ожидания. Вместо установки флага установите дескриптор ожидания. Вместо того, чтобы спать, а затем проверять, установлен ли флаг, ждать команды wait... и ждать с таймаутом, так что если вы просыпаетесь из-за истечения таймера вместо пробуждения, потому что ручка, на которой вы ждали, была уволена по обратному вызову, то вы знаете, что тест не прошел (т.е. обратный вызов не был вызван в течение периода ожидания).