2016-03-22 2 views
0

Я пытаюсь протестировать класс с помощью NUnit, который содержит методы async. Я не знаю, как это сделать правильно.Тестирование свойства, установленного методом async

У меня есть класс с который выглядит следующим образом:

public class EditorViewModel:INotifyPropertyChanged 
{ 
    public void SetIdentifier(string identifier) 
    { 
     CalcContentAsync(); 
    } 

    private async void CalcContentAsync() 
    { 
     await SetContentAsync(); 
     DoSomething(); 
    } 

    private async Task SetContentAsync() 
    { 
     Content = await Task.Run<object>(() => CalculateContent()); 
     RaisePropertyChanged("Content"); 
    } 

    public object Content { get; private set; } 

    ... 
} 

Как я могу написать тест в NUnit, что проверяет, что Content-свойство устанавливается в нужное значение? Я хочу сделать что-то подобное:

[Test] 
public void Content_WhenModifierIsXXX_ReturnsSomeViewModel() 
{ 
    var viewModel = new EditorViewModel(); 

    viewModel.SetIdentifier("XXX"); 

    Assert.That(viewModel.Content, Is.InstanceOf<ISomeContentViewModel>()); 
} 

Но это не работает. Поскольку асинхронный код не был выполнен до утверждения. .

+0

Это просто опечатать, что в SetIdentifier нет async? – Domysee

+0

@ Domysee Я так думаю, потому что он не может скомпилировать другим способом. –

+0

[Избегайте асинхронности] (http://haacked.com/archive/2014/11/11/async-void-methods/). Серьезно - не делайте этого. Вы не можете его протестировать, код вызова никогда не сможет дождаться завершения. –

ответ

1

Ваш метод SetIdentifier является async слишком (или вам нужно, чтобы сделать его async, потому что вы будете ждать операции внутри Тогда ваш метод может выглядит как следующий:

public async Task SetIdentifier(string identifier) 
{ 
    await SetContentAsync(); 
    DoSomething(); 
} 

И теперь вы можете просто ждать его в вашем модульное тестирование:

[Test] 
public async Task Content_WhenModifierIsXXX_ReturnsSomeViewModel() 
{ 
    var viewModel = new EditorViewModel(); 

    await viewModel.SetIdentifier("XXX"); 

    Assert.That(viewModel.Content, Is.InstanceOf<ISomeContentViewModel>()); 
} 

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

[Test] 
public async Task Content_WhenModifierIsXXX_ReturnsSomeViewModel() 
{ 
    Task.Run(async() => 
    { 
     var viewModel = new EditorViewModel(); 

     await viewModel.SetIdentifier("XXX"); 

     Assert.That(viewModel.Content, Is.InstanceOf<ISomeContentViewModel>()); 
    }).GetAwaiter().GetResult(); 
} 

Via MSDN Magazine.

+0

Спасибо за ваш ответ. Я немного изменил код, потому что я пропустил метод. Возможно, проблема «асинхронная пустота» - проблема. – scher

+0

'async void' является частью проблемы. async void указывает, что вы хотите запустить код async, но не дождаться результата. Если вы не ожидаете результата, ваш тест продолжится и начнется тестирование до завершения тестовой настройки. async void в основном используется для событий, потому что вы не хотите, чтобы код события блокировал излучатель события (например, цикл сообщения). Когда вы тестируете, вы должны использовать 'async Task', потому что вы должны дождаться завершения работы, прежде чем тестировать его. Ваш тестовый метод также должен быть асинхронной задачей, чтобы NUnit мог ждать и проверять результаты вашего теста. –

0

При работе с async вы должны всегда вернуть задачу. В противном случае это будет «огонь и забыть», и вы абсолютно не можете взаимодействовать с Task.

Поэтому вы должны изменить подпись SetIdentifier вернуть Task, как это:

public async Task SetIdentifier(string identifier) 
{ 
    await SetContentAsync(); 
    DoSomething(); 
} 

Затем вы можете ждать завершения операции в тесте:

[Test] 
public async void Content_WhenModifierIsXXX_ReturnsSomeViewModel() 
{ 
    var viewModel = new EditorViewModel(); 

    await viewModel.SetIdentifier("XXX"); 

    Assert.That(viewModel.Content, Is.InstanceOf<ISomeContentViewModel>()); 
} 

Или, если ваш испытательный бегун не поддерживает async:

[Test] 
public void Content_WhenModifierIsXXX_ReturnsSomeViewModel() 
{ 
    var viewModel = new EditorViewModel(); 

    viewModel.SetIdentifier("XXX").Wait(); 

    Assert.That(viewModel.Content, Is.InstanceOf<ISomeContentViewModel>()); 
} 
Смежные вопросы