2015-03-16 4 views
1

Проведите единичный тест, который проверяет, что навигация разрешена только в том случае, если Jobs.Count > 0. GetJobsAsync() вызывается во время построения и очищает список вакансий, если не null (получает новый список при каждом его вызове). Похоже, что список вакансий очищается после того, как я вручную добавлю новое задание в качестве условия прохождения модульного теста. Как получить правильное время, чтобы список вакансий не был очищен во время тестирования?Асинхронный метод внутри конструктора, влияющий на модульные тесты

В MyClass конструктор:

this.GetJobsAsync(); 

GetJobsAsync:

private async void GetJobsAsync() 
{ 
    var jobs = await this.dataService.GetJobs(); 
    if (jobs != null) 
    { 
     this.Jobs.Clear(); 

     foreach (var job in jobs) 
     { 
      this.Jobs.Add(new JobViewModel(job)); 
     } 
    } 

    // have the select job command rerun its condition 
    this.SelectJobCommand.RaiseCanExecuteChanged(); 
} 

Unit тест (должен иметь по крайней мере одно задание для навигации, Работа очищается после добавления задания) :

var vm = new MyClass(); 
vm.Jobs.Add(new JobVM(new JobModel())); 
vm.SelectJobCommand.Execute(null);    
Assert.AreEqual(
    NavigationKeys.WizardJob, 
    this.navigationService.CurrentPageKey); 
+2

Вот почему у вас нет методов async void, которые не являются методами верхнего уровня. – Servy

+0

Не лучше ли было бы установить DataService для возвращения задания? Таким образом, поток тестирования имитирует поток продукции как можно точнее. Обычно я делаю это, имея объект Mock DataService в своих модульных тестах. –

+0

Проблема в том, что в реальном приложении у вас есть SynchronizationContext, который поддерживает однопоточность и поддерживает порядок для вас, в то время как в модульном тесте у вас нет одного, так что несколько потоков запущены, и у вас есть гонки состояние. –

ответ

2

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

Понятно, что вы понимаете, что у вас есть состояние гонки. Вы не можете ждать async void, и вы находитесь внутри конструктора.

Как получить правильное время, чтобы список вакансий не был очищен во время теста?

Две вещи. Сначала измените GetJobAsync на async Task вместо async void. Затем, используя шаблон асинхронной инициализации:

public class MyClass 
{ 
    public Task InitializeAsync() 
    { 
     return GetJobsAsync(); 
    } 
} 

И в тестовом модуле:

public async Task TestNavigationAsync() 
{ 
    var vm = new MyClass(); 
    await vm.InitializeAsync(); 

    vm.Jobs.Add(new JobVM(new JobModel())); 
    vm.SelectJobCommand.Execute(null);  

    Assert.AreEqual(NavigationKeys.WizardJob, 
            navigationService.CurrentPageKey); 
} 

Это обеспечит порядок выполнения.

+0

Проблема в том, что с моделью WPF она не очень хорошо работает. В типичном приложении «MyClass» будет создан и инициализирован из объекта getter, где вы не сможете ждать. –

+0

Кто сказал что-нибудь о WPF и свойствах? В любом случае, он может использовать любое событие «Loaded» или «Navigated», чтобы инициировать инициализацию через «AsyncCommand» –

+0

@YuvalItzchakov. Я думаю, что это отлично подойдет для модульного теста, поскольку модульный тест ждет данных, прежде чем продолжить, но я борется с тем, где InitializeAsync будет вызываться в фактическом коде, поскольку он в настоящее время находится в конструкторе ... о, подождите, что вы, возможно, просто ответили, что ... –