Есть ли способ модульного тестирования асинхронного метода?

Я использую Xunit и NMock на платформе .NET. Я тестирую модель представления, в которой метод является асинхронным. Метод создает асинхронную задачу и выполняет ее, поэтому метод немедленно возвращается, а состояние, которое мне нужно проверить, еще не готово.

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

Какие у меня варианты?


person Jiho Han    schedule 23.07.2009    source источник
comment
Какой аспект вы пытаетесь проверить?   -  person Frank Schwieterman    schedule 24.07.2009
comment
Есть сложные решения, но если это просто тест, то нет ничего плохого в параметрах цикла / таймаута / флага.   -  person Ray    schedule 24.07.2009


Ответы (4)


Имеет ли ваш объект какой-либо сигнал о завершении асинхронного метода, например, событие? В этом случае вы можете использовать следующий подход:

[Test]
public void CanTestAsync()
{
    MyObject instance = new MyObject()
    AutoResetEvent waitHandle = new AutoResetEvent(false); 
    // create and attach event handler for the "Finished" event
    EventHandler eventHandler = delegate(object sender, EventArgs e) 
    {
        waitHandle.Set();  // signal that the finished event was raised
    } 
    instance.AsyncMethodFinished += eventHandler;

    // call the async method
    instance.CallAsyncMethod();

    // Wait until the event handler is invoked
    if (!waitHandle.WaitOne(5000, false))  
    {  
        Assert.Fail("Test timed out.");  
    }  
    instance.AsyncMethodFinished -= eventHandler;    
    Assert.AreEqual("expected", instance.ValueToCheck);
}
person Fredrik Mörk    schedule 23.07.2009
comment
По завершении вам, вероятно, следует закрыть дескриптор ожидания, поскольку он использует неуправляемые ресурсы. Я считаю, что эти ресурсы будут очищены автоматически при сборе дескриптора, но обычно я предпочитаю указывать явным образом, когда используются неуправляемые ресурсы. - person Brian Reichle; 29.01.2011

Просто подумал, что вам может понадобиться обновление по этому поводу, поскольку ответ №1 на самом деле рекомендует более старый шаблон для решения этой проблемы.

В .net 4.5 + xUnit 1.9 или выше вы можете просто вернуть задачу и, при желании, использовать ключевое слово async из вашего теста, чтобы xunit дождался завершения теста асинхронно.

См. Эту статью о xUnit.net 1.9

[Fact]
public async Task MyAsyncUnitTest()
{    
  // ... setup code here ...     
  var result = await CallMyAsyncApi(...);     
  // ... assertions here ...
}
person justin.m.chase    schedule 10.05.2012
comment
Ааа ... Всегда приятно, когда в фреймворке есть нативная поддержка ... Приятно знать, спасибо! - person Jiho Han; 24.09.2015
comment
Обратите внимание, что важно возвращать Task, а не void: stackoverflow.com/questions/23824660/ - person lc.; 15.06.2016
comment
Чтобы быть более точным, возвращаемый тип метода должен быть Task, вам фактически не нужно return, если вы используете async / await. - person justin.m.chase; 15.06.2016

Я предпочитаю имитировать и внедрять фактический механизм потоковой передачи, чтобы при тестировании он не был асинхронным. Иногда это невозможно (если потоки метода являются частью фреймворка или иным образом не находятся под вашим контролем).

Если вы не можете управлять созданием потока, тогда ожидая завершения потока каким-либо образом, либо цикл while, либо просто рассчитанное по времени ожидание, сколько времени поток должен принимать, и провал теста, если состояние отсутствует, поскольку оно в любом случае заняло слишком много времени.

person Yishai    schedule 23.07.2009

ознакомьтесь с моей статьей о модульном тестировании приложений Silverlight

http://www.codeproject.com/KB/silverlight/Ag3DemoLOB.aspx

Вот пример модульного тестирования метода, который асинхронно вызывает службу WCF ...

person Mark Caplin    schedule 24.07.2009