2013-03-21 7 views
3

Пожалуйста, обратите внимание на код, как показано ниже. Вызывая GetBrands, свойство Brands будет присвоено надлежащими данными.Как проверить метод async void

public class BrandsViewModel : ViewModelBase 
{ 
    private IEnumerable<Brand> _brands; 
    public IEnumerable<Brand> Brands 
    { 
     get { return _brands; } 
     set { SetProperty(ref _brands, value); } 
    } 

    public async void GetBrands() 
    { 
     // ...... 

     Brands = await _dataHelper.GetFavoriteBrands(); 

     // ...... 
    } 
} 

Но если я проверил его, как показано ниже, тест не удался. Как подождать асинхронный вызов внутри метода GetBrands?

[TestMethod] 
public void AllBrandsTest() 
{ 
    BrandsViewModel viewModel = new BrandsViewModel(); 
    viewModel.GetBrands(); 
    Assert.IsTrue(viewModel.Brands.Any()); 
} 
+3

Пожалуйста, прочтите/смотреть это: http://blogs.msdn.com/b/ lucian/archive/2013/02/18/talk-the-new-async-design-patternss.aspx В основном он говорит: Не используйте 'async void', кроме обработчиков событий. –

+0

@ DanielHilgarth Спасибо, Даниэль. Я реорганизовал свой код, и он просто работает как шарм. – Shinbo

ответ

8

Простой ответ здесь: не делайте это async void. На самом деле, не сделать что-то async void, если он абсолютно не должен работать как обработчик событий. То, что async void проигрывает точно вещи, которые вы хотите здесь для своего теста (и, предположительно, для вашего реального кода).

Вместо этого сделайте это async Task, и теперь у вас есть возможность дождаться завершения (с таймаутом)/добавить продолжение и проверить, завершилось ли это с успехом или исключением.

Это единственное изменение слова, чтобы:

public async Task GetBrands() 
{ 
    // ...... 

    Brands = await _dataHelper.GetFavoriteBrands(); 

    // ...... 
} 

, а затем в тесте:

[TestMethod] 
public async Task AllBrandsTest() 
{ 
    BrandsViewModel viewModel = new BrandsViewModel(); 
    var task = viewModel.GetBrands(); 
    Assert.IsTrue(task.Wait(YOUR_TIMEOUT), "failed to load in time"); 
    Assert.IsTrue(viewModel.Brands.Any(), "no brands"); 
} 
+0

Почему вы сохранили тест 'async', если вы не используете' await' в нем? – svick

+0

@svick это вопрос для OP, который также не «ждет» в нем :) –

+0

@svick Моя ошибка. Я скорректировал свой тестовый код. Нет необходимости сохранять асинхронный режим, если в методе не ждать. – Shinbo

1

Ваша модель (DTO) заселяет себя (доступ к данным). Это слишком много для одного класса. Обычно, когда вы спрашиваете себя «Как я могу проверить это», пришло время для рефакторинга. Создать отдельный класс для доступа к данным:

BrandsViewModel viewModel = new BrandsViewModel(); 
var brandAccess = new BrandsDataAccess(); 
viewModel.Brands = await brandAccess.GetAllBrands(); 
Assert.IsTrue(viewModel.Brands.Any()); 

Теперь вы можете проверить BrandsDataAccess.GetAllBrands().

+0

Куда делся «асинк»? Я имею в виду: исходный код «async», а ваш нет, поэтому я не думаю, что это хорошая замена. – svick

+0

@svick это принцип, который имеет значение, а не реализация. См. Править. – CodeCaster

+0

@CodeCaster Не могли бы вы объяснить свою точку зрения еще больше? Что касается принципа единой ответственности, я думаю, что заполнение его собственного имущества в одном классе приемлемо. Не так ли? – Shinbo

Смежные вопросы