Итак, я пишу модульные тесты для одной из моих моделей просмотра в мобильном приложении Xamarin. Метод я тестирую выглядит так:Недетерминированные модульные тесты с Rx, Xamarin
public async Task RefreshItems()
{
var departamentsObservable = _dataService.GetDepartaments();
departamentsObservable.ObserveOn(SynchronizationContext.Current).Subscribe(items =>
{
Departaments.ReplaceWithRange(items);
});
await departamentsObservable.FirstOrDefaultAsync();
}
_dataService.GetDepartaments();
метод возвращает IObservable<IEnumerable<Departament>>
.
Я использую Observable
и Subscribe
вместо простого метода, который возвращает Task<IEnumerable<Departament>>
, потому что в моем случае Observable
будет «вернуться» в два раза (один раз с данными из кэша и другого времени с недавно извлеченными данными формы сетью).
Для тестирования я конечно фиктивный _dataService.GetDepartaments();
метод так:
public IObservable<IEnumerable<Departament>> GetDepartaments()
{
return Observable.Return(MockData.Departaments);
}
Так метод немедленно возвращает макет данных.
И мой тест для RefreshItems
метода выглядит следующим образом:
[Fact]
public async Task RefreshItemsTest()
{
await _viewModel.RefreshItems();
Assert.Equal(MockData.Departaments, _viewModel.Departaments,
new DepartamentComparer());
}
Проблема заключается в том, что этот тест случайным образом выходит из строя (1 в 10 раз примерно). В принципе модель Departaments
, которая должна обновляться, когда Observable
«возвращает», пуста.
Я должен добавить, что я использую xUnit 2.1.0 тестовую среду и консольный консоль xUnit в Xamarin Studio.
EDIT: внушения Enigmativity проливает последовательность не содержит элементов только исключение при запуске в тестовом бегуна. Ниже приведен минимальный пример Уокинг код для демонстрации вопрос:
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Reactive.Linq;
using System.Threading;
using System.Collections.Generic;
namespace TestApp
{
public class TestViewModel
{
public ObservableCollection<TestDepartament> Departaments { get; set; }
private ITestDataService _dataService;
public TestViewModel(ITestDataService dataService)
{
_dataService = dataService;
Departaments = new ObservableCollection<TestDepartament>();
}
public async Task RefreshItems()
{
var facultiesObservable = _dataService.GetDepartaments();
await facultiesObservable.ObserveOn(SynchronizationContext.Current).Do(items =>
{
Departaments.Clear();
foreach(var item in items)
Departaments.Add(item);
});
}
}
public interface ITestDataService
{
IObservable<IEnumerable<TestDepartament>> GetDepartaments();
}
public class MockDataService : ITestDataService
{
public IObservable<IEnumerable<TestDepartament>> GetDepartaments()
{
return Observable.Return(TestMockData.Departaments);
}
}
public static class TestMockData
{
public static List<TestDepartament> Departaments
{
get
{
var departaments = new List<TestDepartament>();
for (int i = 0; i < 15; i++)
{
departaments.Add(new TestDepartament
{
Name = $"Departament {i}",
ImageUrl = $"departament_{i}_image_url",
ContentUrl = $"departament_{i}_content_url",
});
}
return departaments;
}
}
}
public class TestDepartament
{
public string ContentUrl { get; set; }
public string Name { get; set; }
public string ImageUrl { get; set; }
}
}
И это XUnit тест:
public class DepartamentsViewModelTests
{
private readonly TestViewModel _viewModel;
public DepartamentsViewModelTests()
{
var dataService = new MockDataService();
_viewModel = new TestViewModel(dataService);
}
[Fact]
public async Task RefreshItemsTest()
{
await _viewModel.RefreshItems();
Assert.Equal(TestMockData.Departaments, _viewModel.Departaments);
}
}
Вы отлажена и сравнили результаты вручную? Возможно, «ДепартаментКомпьютер» испорчен? –
@ m-y Спасибо за ваш ответ. Да, я отлаживал свой тест, а длина коллекции «Депозиты» в представлении модели действительно равна 0, когда тест терпит неудачу. – Andrius