Как протестировать асинхронный метод с помощью NUnit (или, возможно, с другой платформой)?

у меня есть ASP.NET веб-приложение API с ApiController, который имеет асинхронные методы, возвращающие Task<> объекты и отмечены знаком async ключевое слово.

public class MyApiController : ApiController
{
    public async Task<MyData> GetDataById(string id)
    {
        ...
    }
}

как я могу написать тесты NUnit для асинхронных методов ApiController? Если мне нужно использовать другую платформу тестирования, я тоже открыт для этого. Я довольно новичок в модульном тестировании .NET в целом, поэтому меня интересует изучение лучших практик.

5 ответов


на сегодняшний день (7/2/2014) асинхронное тестирование поддерживается:

в первых двух фреймворках метод тестирования должен иметь следующее подпись:

[TestMethod]
public async Task MyTestMethod()
{
   ...
   var result = await objectUnderTest.TestedAsyncMethod(...);
   // Make assertions
}

NUnit, кроме этой подписи, поддерживает эту:

public async void MyTestMethod()

конечно, внутри любого из этих методов вы можете использовать await для вызова и ожидания асинхронных методов.

если вы используете платформу тестирования, которая не поддерживает асинхронные методы тестирования, то единственный способ сделать это-вызвать асинхронный метод и подождать, пока он не завершится, используя любой из обычных способов:await, читать Result свойства Task<T> возвращается async метод, используя любой из обычных методов ожидания Task и так далее. После ожидания вы можете делать все утверждения, как обычно. Например, с помощью MSTest:

[TestMethod]
public void MyTestMethod()
{
    ...
    Task<MyResultClass> task = objectUnderTest.MyAsyncMethod(...);
    // Make anything that waits for the method to end
    MyResultClass result = task.Result;

    // Make the assertions
    Assert.IsNotNull(result);
    ...
}

Мне кажется, что в NUnit 2.6 нет встроенной поддержки для тестирования асинхронных методов, возвращающих задачи. Лучший вариант, который я вижу прямо сейчас, - использовать собственную платформу UnitTesting Visual Studio или xUnit.net поскольку оба поддерживают асинхронные тесты.

С помощью Visual Studio UnitTesting framework я могу писать асинхронные тесты следующим образом:

using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class TestAsyncMethods
{
    [TestMethod]
    public async Task TestGetBinBuildById()
    {
         ...
         var rslt = await obj.GetAsync();
         Assert.AreEqual(rslt, expected);
    }
}

имейте в виду, что серия NUnit 2.6, как и предыдущие, построена для целевой платформы .NET 2.0. Так, Нанит можно сделать только тем же, чем вы могли себе код, в целевой сборке .Объем 2.0.

в частности, вы не можете пометить свой метод тестирования как асинхронные и ожидать Нанит, чтобы сделать что-нибудь особенное.

вы можете, однако,

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

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

другой вариант-использовать NUnitLite. NUnitLite 0.8 поддерживает атрибут [асинхронный], который позволит продолжить другие тесты, пока ваш асинхронный тест завершен. Преимущество атрибута заключается в том, что он позволяет асинхронным тестам работать в .NET 2.0-4.0

в настоящее время у нас нет .NET 4.5 сборки NUnitLite, но она будет добавлена в ближайшее время, и мы работаем над изменением, которое будет использовать [асинхронный] необязательно в этой среде. На данный момент Вы можете легко загрузить и перекомпилировать исходный код для .NET 4.5.

в будущем, посмотрите на NUnit 3.0 для поддержки асинхронных методов полностью вместе с общее параллельное выполнение тестов на нескольких потоках или в нескольких процессах.


Я в процессе преобразования некоторых из моих методов в async. Заставить это работать с NUnit было довольно просто.

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

в моем примере у меня был метод:

    public string SendUpdateRequestToPlayer(long playerId)

и он был протестирован в nUnit так:

     string result = mgr.SendUpdateRequestToPlayer(player.Id.Value);
     Assert.AreEqual("Status update request sent", result);
     mocks.VerifyAll();

теперь, когда я изменили метод SendUpdateRequestToPlayer для асинхронного

      public async Task<string> SendUpdateRequestToPlayer(long playerId)

мне просто пришлось изменить мои тесты на Wait для выполнения задачи:

 Task<string> task = mgr.SendUpdateRequestToPlayer(player.Id.Value);
 task.Wait(); // The task runs to completion on a background thread
 Assert.AreEqual("Status update request sent", task.Result);
 mocks.VerifyAll();

Это действительно зависит от того, что они делают. Обычно они будут зависеть от чего-то else которые предоставляет Task<T> или что-то подобное. В этом случае вы можете предоставить поддельные зависимости, которые позволят вам контролировать все это мелкозернистым способом. У меня есть прототип "машины времени", которая позволяет вам предварительно программировать задачи для выполнения в определенное искусственное время, а затем перемещать Время вперед и выполнять утверждения по мере продвижения. Есть блоге о это который вы можете найти полезным. Как я уже сказал, это всего лишь прототип, и он не подходит для все сценарии - но это может подойти вам.

Стивен Клири также имеет несколько сообщений в блоге вокруг модульного тестирования (1, 2), принимая немного другой подход, наряду с пакета NuGet вы можете найти полезную.

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