Рекомендуемый способ проверки планировщика / газа
Я нахожусь в процессе переписывания одного маленького WPF-приложения, которое я написал, чтобы использовать ReactiveUI, чтобы получить представление о библиотеке.
Мне очень нравится это до сих пор!
Теперь я наткнулся на Throttle
метод и хотите использовать его при применении фильтра к коллекции.
Это моя ViewModel:
namespace ReactiveUIThrottle
{
public class MainViewModel : ReactiveObject
{
private string _filter;
public string Filter { get => _filter; set => this.RaiseAndSetIfChanged(ref _filter, value); }
private readonly ReactiveList<Person> _persons = new ReactiveList<Person>();
private readonly ObservableAsPropertyHelper<IReactiveDerivedList<Person>> _filteredPersons;
public IReactiveDerivedList<Person> Persons => _filteredPersons.Value;
public MainViewModel()
{
Filter = string.Empty;
_persons.AddRange(new[]
{
new Person("Peter"),
new Person("Jane"),
new Person("Jon"),
new Person("Marc"),
new Person("Heinz")
});
var filterPersonsCommand = ReactiveCommand.CreateFromTask<string, IReactiveDerivedList<Person>>(FilterPersons);
this.WhenAnyValue(x => x.Filter)
// to see the problem
.Throttle(TimeSpan.FromMilliseconds(2000), RxApp.MainThreadScheduler)
.InvokeCommand(filterPersonsCommand);
_filteredPersons = filterPersonsCommand.ToProperty(this, vm => vm.Persons, _persons.CreateDerivedCollection(p => p));
}
private async Task<IReactiveDerivedList<Person>> FilterPersons(string filter)
{
await Task.Delay(500); // Lets say this takes some time
return _persons.CreateDerivedCollection(p => p, p => p.Name.Contains(filter));
}
}
}
Сама фильтрация работает как чудо, а также регулирование при использовании графического интерфейса.
Однако я бы хотел протестировать поведение фильтрации, и это моя первая попытка:
[Test]
public void FilterPersonsByName()
{
var sut = new MainViewModel();
sut.Persons.Should().HaveCount(5);
sut.Filter = "J";
sut.Persons.Should().HaveCount(2);
}
Этот тест не пройден, потому что в коллекции все еще 5 человек.
Когда я избавлюсь от await Task.Delay(500)
в FilterPersons
тогда тест пройдет, но займет 2 секунды (от дросселя).
1) Есть ли способ, чтобы дроссель был мгновенным в тесте, чтобы ускорить тест?
2) Как я могу проверить асинхронное поведение в моем фильтре?
Я использую ReactiveUI 7.x
1 ответ
Короткие ответы:
- Да, убедившись, что вы используете
CurrentThreadScheduler.Instance
при тестировании - Вместо того, чтобы использовать
CurrentThreadScheduler
, использоватьTestScheduler
и вручную продвинуть его
Более длинный ответ заключается в том, что вам нужно убедиться, что ваши модульные тесты могут контролировать планировщик, используемый вашей тестируемой системой (SUT). По умолчанию вы обычно хотите использовать CurrentThreadScheduler.Instance
чтобы все происходило "мгновенно" без необходимости вручную планировать работу. Но когда вы хотите написать тесты, которые проверяют время, вы используете TestScheduler
вместо.
Если, как вы, кажется, вы используете RxApp.*Scheduler
, посмотрите на With
метод расширения, который можно использовать так:
(new TestScheduler()).With(sched => {
// write test logic here, and RxApp.*Scheduler will resolve to the chosen TestScheduler
});
Я стараюсь не использовать RxApp
окружающий контекст в целом по той же причине, что я избегаю всех окружающих контекстов: они являются общим состоянием и, как следствие, могут вызвать проблемы. Вместо этого я ввожу IScheduler
(или два) в мое SUT как зависимость.