Async CTP, модульное тестирование асинхронного метода ViewModel - PullRequest
3 голосов
/ 31 августа 2011

У меня есть модульный тест (с использованием MSTest), например:

[TestMethod]
public void MyTest()
{
    var viewModel = new MyViewModel();
    viewModel.Run();
    //Assert something here
}

Run - это асинхронный метод, который возвращает void.

Допустим, Run реализован так:

public async void Run()
{
    //Show a busy indicator here

    try
    {
        var result = await myAsyncModelClass.LongRunningOperation();

        //Use the results here
    }
    finally
    {
        //Hide the busy indicator here
    }
}

myAsyncModelClass.LongRunningOperation(), сам по себе является асинхронным методом, который возвращает значение Task<T>, где T - результат, который интересует моя ViewModel.

Моя проблема в том, что мой тест запускает метод Run асинхронно, поэтому мои утверждения вызываются до завершения методов Run. Как ни странно, b / c блок finally никогда не достигается, когда я ставлю точку останова, поскольку утверждения не выполняются. Как сохранить синхронный метод Run для возможности его модульного тестирования?

У меня также есть юнит-тест myAsyncModelClass.LongRunningOperation(), но я просто вызываю Task<T>.Wait(), так как он возвращает задачу. Это делает его синхронным при модульном тестировании.

Кроме того, я хотел бы отметить, что Run() магически вызывается ICommand средой MVVM. void может быть, а может и не быть обязательным типом возврата, мне придется попробовать его.

Ответы [ 2 ]

15 голосов
/ 31 августа 2011

Асинхронным методам нужен контекст для «возврата к».Поскольку MSTests выполняются в пуле потоков, по умолчанию все асинхронные методы продолжаются и в потоке пула потоков (и не блокируют метод MSTest).

В примере (C# Testing) Unit Testing (в вашей установке Async CTPкаталог), есть тип с именем GeneralThreadAffineContext, который можно использовать следующим образом:

[TestMethod]
public void MyTest()
{
  MyViewModel viewModel = null;
  GeneralThreadAffineContext.Run(() =>
  {
    viewModel = new MyViewModel();
    viewModel.Run();
  });
  //Assert something here
}

Существуют также определенные контексты WPF и WinForms, но аффинно-потоковый контекст должен работать для общих ViewModels (которые нене использовать явно Dispatcher).

Обновление 2012-02-05: Если вы можете изменить свой метод ViewModel, чтобы он возвращал Task, тогда у вас есть другая опция:новая библиотека AsyncUnitTests .Установите этот пакет NuGet, измените TestClass на AsyncTestClass, и ваши асинхронные модульные тесты могут быть написаны гораздо более естественно:

[TestMethod]
public async void MyTest()
{
  MyViewModel viewModel = new MyViewModel();
  await viewModel.Run();
  //Assert something here
}

Обновление 2012-09-04: VisualStudio 2012 включает в себя async модульное тестирование, поэтому вам больше не нужна библиотека AsyncUnitTests:

[TestMethod]
public async Task MyTest()
{
  MyViewModel viewModel = new MyViewModel();
  await viewModel.Run();
  //Assert something here
}
3 голосов
/ 15 июля 2012

Начиная с Visual Studio 2012 MSTest поддерживает методы асинхронного тестирования.Просто помните, что они должны вернуть Task вместо void:

[TestMethod]
public async Task MyTest()
{
  MyViewModel viewModel = new MyViewModel();
  await viewModel.Run();
  //Assert something here
}
...