public TogglDataSource( ITogglApi api, ITogglDatabase database, ITimeService timeService, Func <ITogglDataSource, ISyncManager> createSyncManager, IAnalyticsService analyticsService) { Ensure.Argument.IsNotNull(api, nameof(api)); Ensure.Argument.IsNotNull(database, nameof(database)); Ensure.Argument.IsNotNull(timeService, nameof(timeService)); Ensure.Argument.IsNotNull(createSyncManager, nameof(createSyncManager)); Ensure.Argument.IsNotNull(analyticsService, nameof(analyticsService)); this.database = database; User = new UserDataSource(database.User); Tags = new TagsDataSource(database.Tags); Tasks = new TasksDataSource(database.Tasks); Clients = new ClientsDataSource(database.Clients); Projects = new ProjectsDataSource(database.Projects); Workspaces = new WorkspacesDataSource(database.Workspaces); Preferences = new PreferencesDataSource(database.Preferences); WorkspaceFeatures = new WorkspaceFeaturesDataSource(database.WorkspaceFeatures); TimeEntries = new TimeEntriesDataSource(database.TimeEntries, timeService, analyticsService); SyncManager = createSyncManager(this); ReportsProvider = new ReportsProvider(api, database); FeedbackApi = api.Feedback; }
public void CachesTheApiResultsInMemorySoTheApiIsNotCalledTwiceForTheSameProjects( NonEmptyArray <NonNegativeInt> projectIds) { var actualProjectIds = projectIds.Get.Select(i => (long)i.Get).Distinct().ToArray(); var idCount = actualProjectIds.Length; if (idCount < 2) { return; } var dbProjectCount = (int)Math.Floor((float)idCount / 2); var apiProjectCount = idCount - dbProjectCount; var projectsInDb = actualProjectIds.Take(dbProjectCount).ToArray(); var projectsInApi = actualProjectIds.TakeLast(apiProjectCount).ToArray(); var summaries = getSummaryList(actualProjectIds); apiProjectsSummary.ProjectsSummaries.Returns(summaries); configureRepositoryToReturn(projectsInDb, projectsInApi); configureApiToReturn(projectsInApi); ReportsProvider.GetProjectSummary(workspaceId, DateTimeOffset.Now.AddDays(-7), DateTimeOffset.Now).Wait(); ReportsProvider.GetProjectSummary(workspaceId, DateTimeOffset.Now.AddDays(-7), DateTimeOffset.Now).Wait(); ProjectsApi.Received(1) .Search(workspaceId, Arg.Is <long[]>( calledIds => ensureExpectedIdsAreReturned(calledIds, projectsInApi))); }
public async Task ReturnsSegmentsJustOnceWhenChangingDateRange() { var segments = new ChartSegment[2] { new ChartSegment("Project 1", "Client 1", 50f, 10, 0, "ff0000"), new ChartSegment("Project 2", "Client 2", 50f, 10, 0, "00ff00") }; var projectsNotSyncedCount = 0; var currentDate = new DateTimeOffset(2018, 5, 23, 0, 0, 0, TimeSpan.Zero); var start = new DateTimeOffset(2018, 5, 1, 0, 0, 0, TimeSpan.Zero); var end = new DateTimeOffset(2018, 5, 7, 0, 0, 0, TimeSpan.Zero); TimeService.CurrentDateTime.Returns(currentDate); var delayed = Observable .Return(new ProjectSummaryReport(segments, projectsNotSyncedCount)) .Delay(TimeSpan.FromMilliseconds(100)); var instant = Observable .Return(new ProjectSummaryReport(segments, projectsNotSyncedCount)); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(delayed, instant); await Initialize(); ViewModel.ChangeDateRangeCommand.Execute( ReportsDateRangeParameter.WithDates(start, end)); await delayed; ViewModel.Segments.Count.Should().Be(segments.Length); }
public IActionResult Uber() { var dates = GetDates(); ReportsProvider.StartReport(Reports.Uber, _amo, _processQueue, _gSheets, dates.Item1, dates.Item2); return(Ok("Requested.")); }
public static void RegisterAllServices(this SimpleServiceContainer store) { var repoFactory = new GenericRepositoryFactory(store, store); store.RegisterSingleton <IRepositoryFactory>(c => repoFactory); var reports = new ReportsProvider(); store.RegisterSingleton <IReportsProvider>(reports); store.RegisterSingleton <IReportsStore>(reports); RegisterRepositories(repoFactory); }
public void DoesNotCallTheApiIfAllProjectsAreInTheDatabase(NonEmptyArray <NonNegativeInt> projectIds) { var actualProjectIds = projectIds.Get.Select(i => (long)i.Get).Distinct().ToArray(); var summaries = getSummaryList(actualProjectIds); apiProjectsSummary.ProjectsSummaries.Returns(summaries); configureRepositoryToReturn(actualProjectIds); ReportsProvider.GetProjectSummary(workspaceId, DateTimeOffset.Now.AddDays(-7), DateTimeOffset.Now).Wait(); ProjectsApi.DidNotReceive().Search(Arg.Any <long>(), Arg.Any <long[]>()); }
public async Task IsSetToTrueWhenAReportIsLoading() { var now = DateTimeOffset.Now; TimeService.CurrentDateTime.Returns(now); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Never <ProjectSummaryReport>()); await Initialize(); ViewModel.IsLoading.Should().BeTrue(); }
public async Task IsSetToFalseWhenLoadingIsCompleted() { var now = DateTimeOffset.Now; TimeService.CurrentDateTime.Returns(now); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Return(new ProjectSummaryReport(new ChartSegment[0]))); ViewModel.Prepare(WorkspaceId); await ViewModel.Initialize(); ViewModel.IsLoading.Should().BeFalse(); }
[HttpGet("{from},{to}")] //Запрашиваем отчёт для диапазона дат public IActionResult CorporateSales(string from, string to) { if (!long.TryParse(from, out long dateFrom) & !long.TryParse(to, out long dateTo)) { return(BadRequest("Incorrect dates")); } ReportsProvider.StartReport(Reports.CorporateSales, _amo, _processQueue, _gSheets, dateFrom, dateTo); return(Ok("Requested.")); }
public async Task IsSetToFalseWhenLoadingOverBecauseOfAnError() { var now = DateTimeOffset.Now; TimeService.CurrentDateTime.Returns(now); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Throw <ProjectSummaryReport>(new Exception())); ViewModel.Prepare(WorkspaceId); await ViewModel.Initialize(); ViewModel.IsLoading.Should().BeFalse(); }
public IActionResult Calls() { var now = DateTime.UtcNow.AddHours(3); var to = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0, DateTimeKind.Utc).AddHours(-3).AddSeconds(-1); var from = to.AddSeconds(1).AddDays(-1); long dateFrom = ((DateTimeOffset)from).ToUnixTimeSeconds(); long dateTo = ((DateTimeOffset)to).ToUnixTimeSeconds(); ReportsProvider.StartReport(Reports.SuccessCalls, _amo, _processQueue, _gSheets, dateFrom, dateTo); return(Ok("Requested.")); }
[HttpGet("{to}")] //Запрашиваем отчёт для диапазона дат public IActionResult CorporateSales(string to) { if (!long.TryParse(to, out long dateTo)) { return(BadRequest("Incorrect dates")); } var dates = GetDates(dateTo); ReportsProvider.StartReport(Reports.CorporateSales, _amo, _processQueue, _gSheets, dates.Item1, dates.Item2); return(Ok("Requested.")); }
public async Task IsSetToTrueWhenAReportIsLoading() { var now = DateTimeOffset.Now; TimeService.CurrentDateTime.Returns(now); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Never <ProjectSummaryReport>()); await Initialize(); TestScheduler.Start(); isLoadingObserver.Messages.Last().Value.Value.Should().BeTrue(); }
public void QueriesTheDatabaseForFindingProjects(NonEmptyArray <NonNegativeInt> projectIds) { var actualProjectIds = projectIds.Get.Select(i => (long)i.Get).Distinct().ToArray(); var summaries = getSummaryList(actualProjectIds); apiProjectsSummary.ProjectsSummaries.Returns(summaries); configureRepositoryToReturn(actualProjectIds); ReportsProvider.GetProjectSummary(workspaceId, DateTimeOffset.Now.AddDays(-7), DateTimeOffset.Now).Wait(); ProjectsRepository.Received() .GetById(Arg.Is <long>(id => Array.IndexOf(actualProjectIds, id) >= 0)); }
public async Task ShouldNotTriggerAReportReloadWhenSelectionIsCancelled() { TimeService.CurrentDateTime.Returns(DateTimeOffset.Now); await ViewModel.Initialize(); DialogService.Select(Arg.Any <string>(), Arg.Any <IEnumerable <(string, IThreadSafeWorkspace)> >(), Arg.Any <int>()) .Returns(Observable.Return <IThreadSafeWorkspace>(null)); ViewModel.SelectWorkspace.Execute(); TestScheduler.Start(); await ReportsProvider.DidNotReceive().GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()); }
public async Task IsSetToFalseWhenLoadingIsCompleted() { var now = DateTimeOffset.Now; var projectsNotSyncedCount = 0; TimeService.CurrentDateTime.Returns(now); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Return(new ProjectSummaryReport(new ChartSegment[0], projectsNotSyncedCount))); await Initialize(); TestScheduler.Start(); isLoadingObserver.Messages.Last().Value.Value.Should().BeFalse(); }
public void FiresACallToLoadReports(DateTimeOffset now) { var date = now.Date; TimeService.CurrentDateTime.Returns(now); var expectedStartDate = date.AddDays(1 - (int)date.DayOfWeek); ViewModel.Prepare(WorkspaceId); ViewModel.Initialize().Wait(); ReportsProvider.Received().GetProjectSummary( WorkspaceId, expectedStartDate, expectedStartDate.AddDays(6)); }
public TogglDataSource( ITogglApi api, ITogglDatabase database, ITimeService timeService, IErrorHandlingService errorHandlingService, IBackgroundService backgroundService, Func <ITogglDataSource, ISyncManager> createSyncManager, TimeSpan minimumTimeInBackgroundForFullSync, INotificationService notificationService, IApplicationShortcutCreator shortcutCreator, IAnalyticsService analyticsService) { Ensure.Argument.IsNotNull(api, nameof(api)); Ensure.Argument.IsNotNull(database, nameof(database)); Ensure.Argument.IsNotNull(timeService, nameof(timeService)); Ensure.Argument.IsNotNull(notificationService, nameof(notificationService)); Ensure.Argument.IsNotNull(errorHandlingService, nameof(errorHandlingService)); Ensure.Argument.IsNotNull(backgroundService, nameof(backgroundService)); Ensure.Argument.IsNotNull(createSyncManager, nameof(createSyncManager)); Ensure.Argument.IsNotNull(shortcutCreator, nameof(shortcutCreator)); Ensure.Argument.IsNotNull(analyticsService, nameof(analyticsService)); this.database = database; this.timeService = timeService; this.shortcutCreator = shortcutCreator; this.backgroundService = backgroundService; this.notificationService = notificationService; this.errorHandlingService = errorHandlingService; this.minimumTimeInBackgroundForFullSync = minimumTimeInBackgroundForFullSync; User = new UserDataSource(database.User); Tags = new TagsDataSource(database.Tags); Tasks = new TasksDataSource(database.Tasks); Clients = new ClientsDataSource(database.Clients); Projects = new ProjectsDataSource(database.Projects); Workspaces = new WorkspacesDataSource(database.Workspaces); Preferences = new PreferencesDataSource(database.Preferences); WorkspaceFeatures = new WorkspaceFeaturesDataSource(database.WorkspaceFeatures); TimeEntries = new TimeEntriesDataSource(database.TimeEntries, timeService, analyticsService); this.createSyncManager = createSyncManager; CreateNewSyncManager(); ReportsProvider = new ReportsProvider(api, database); FeedbackApi = api.Feedback; isLoggedIn = true; }
public void CreatesAChartSegmentWithNoProjectIfThereAreNullProjectIdsAmongTheApiResults( NonNegativeInt[] projectIds) { var actualProjectIds = projectIds.Select(i => (long)i.Get).Distinct().ToArray(); var summaries = getSummaryList(actualProjectIds); summaries.Add(new ProjectSummary()); apiProjectsSummary.ProjectsSummaries.Returns(summaries); configureRepositoryToReturn(actualProjectIds); var report = ReportsProvider .GetProjectSummary(workspaceId, DateTimeOffset.Now.AddDays(-7), DateTimeOffset.Now).Wait(); report.Segments.Single(s => s.Color == Color.NoProject).ProjectName.Should().Be(Resources.NoProject); }
public void IsSetToNullIfTheTotalTimeOfAReportIsZero(DateTimeOffset now) { var date = now.Date; var projectsNotSyncedCount = 0; TimeService.CurrentDateTime.Returns(now); var expectedStartDate = date.AddDays(1 - (int)date.DayOfWeek); ReportsProvider.GetProjectSummary( WorkspaceId, expectedStartDate, expectedStartDate.AddDays(6)) .Returns(Observable.Return(new ProjectSummaryReport(new ChartSegment[0], projectsNotSyncedCount))); ViewModel.Initialize().Wait(); ViewModel.BillablePercentage.Should().BeNull(); }
public async Task IsSetToTrueWhenAReportIsLoading() { var loadingObserver = TestScheduler.CreateObserver <bool>(); var now = DateTimeOffset.Now; TimeService.CurrentDateTime.Returns(now); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Never <ProjectSummaryReport>()); ViewModel.IsLoadingObservable.Subscribe(loadingObserver); await Initialize(); TestScheduler.Start(); var isLoading = loadingObserver.Values().Last(); isLoading.Should().BeTrue(); }
public async Task ShouldTriggerReloadForEveryAppearance(int numberOfAppearances) { TimeService.CurrentDateTime.Returns(DateTimeOffset.Now); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .ReturnsForAnyArgs(Observable.Empty <ProjectSummaryReport>(SchedulerProvider.TestScheduler)); await ViewModel.Initialize(); ViewModel.ViewAppeared(); // First call is skipped for (int i = 0; i < numberOfAppearances; ++i) { ViewModel.ViewAppeared(); } TestScheduler.Start(); ReportsProvider.Received(numberOfAppearances).GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()); }
public TogglDataSource( ITogglApi api, ITogglDatabase database, ITimeService timeService, IApiErrorHandlingService apiErrorHandlingService, IBackgroundService backgroundService, Func <ITogglDataSource, ISyncManager> createSyncManager, TimeSpan minimumTimeInBackgroundForFullSync, IApplicationShortcutCreator shortcutCreator) { Ensure.Argument.IsNotNull(api, nameof(api)); Ensure.Argument.IsNotNull(database, nameof(database)); Ensure.Argument.IsNotNull(timeService, nameof(timeService)); Ensure.Argument.IsNotNull(apiErrorHandlingService, nameof(apiErrorHandlingService)); Ensure.Argument.IsNotNull(backgroundService, nameof(backgroundService)); Ensure.Argument.IsNotNull(createSyncManager, nameof(createSyncManager)); Ensure.Argument.IsNotNull(shortcutCreator, nameof(shortcutCreator)); this.database = database; this.apiErrorHandlingService = apiErrorHandlingService; this.backgroundService = backgroundService; this.shortcutCreator = shortcutCreator; this.minimumTimeInBackgroundForFullSync = minimumTimeInBackgroundForFullSync; User = new UserDataSource(database.User, timeService); Tags = new TagsDataSource(database.IdProvider, database.Tags, timeService); Tasks = new TasksDataSource(database.Tasks); Clients = new ClientsDataSource(database.IdProvider, database.Clients, timeService); Preferences = new PreferencesDataSource(database.Preferences); Projects = new ProjectsDataSource(database.IdProvider, database.Projects, timeService); TimeEntries = new TimeEntriesDataSource(database.TimeEntries, timeService); Workspaces = new WorkspacesDataSource(database.Workspaces); WorkspaceFeatures = new WorkspaceFeaturesDataSource(database.WorkspaceFeatures); SyncManager = createSyncManager(this); ReportsProvider = new ReportsProvider(api, database); errorHandlingDisposable = SyncManager.ProgressObservable.Subscribe(onSyncError); isLoggedIn = true; }
public async Task ShouldTriggerAReportReload() { TimeService.CurrentDateTime.Returns(DateTimeOffset.Now); await ViewModel.Initialize(); TestScheduler.Start(); var mockWorkspace = new MockWorkspace { Id = WorkspaceId + 1 }; DialogService.Select(Arg.Any <string>(), Arg.Any <IEnumerable <(string, IThreadSafeWorkspace)> >(), Arg.Any <int>()) .Returns(Observable.Return(mockWorkspace)); ViewModel.SelectWorkspace.Execute(); TestScheduler.Start(); await ReportsProvider.Received().GetProjectSummary(Arg.Is(mockWorkspace.Id), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()); }
public void IsSetToNullIfTheTotalTimeOfAReportIsZero() { var billableObserver = TestScheduler.CreateObserver <float?>(); var projectsNotSyncedCount = 0; TimeService.CurrentDateTime.Returns(DateTime.Now); TimeService.MidnightObservable.Returns(Observable.Never <DateTimeOffset>()); ReportsProvider .GetProjectSummary(WorkspaceId, Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Return(new ProjectSummaryReport(new ChartSegment[0], projectsNotSyncedCount))); ViewModel.BillablePercentageObservable.Subscribe(billableObserver); Initialize().Wait(); TestScheduler.Start(); var billablePercentage = billableObserver.Values().Last(); billablePercentage.Should().BeNull(); }
public void ReturnsOnlyOneListIfItQueriesTheApi(NonEmptyArray <NonNegativeInt> projectIds) { var actualProjectIds = projectIds.Get.Select(i => (long)i.Get).Distinct().ToArray(); if (actualProjectIds.Length < 2) { return; } var projectsInDb = actualProjectIds.Where((i, id) => i % 2 == 0).ToArray(); var projectsInApi = actualProjectIds.Where((i, id) => i % 2 != 0).ToArray(); var summaries = getSummaryList(actualProjectIds); apiProjectsSummary.ProjectsSummaries.Returns(summaries); configureRepositoryToReturn(projectsInDb, projectsInApi); configureApiToReturn(projectsInApi); var lists = ReportsProvider.GetProjectSummary(workspaceId, DateTimeOffset.Now.AddDays(-7), DateTimeOffset.Now).ToList().Wait(); lists.Should().HaveCount(1); }
public void ReturnsTheProjectOrderedByTotalTimeTracked(NonNegativeInt[] projectIds) { var actualProjectIds = projectIds.Select(i => (long)i.Get).Distinct().ToArray(); var summaries = getSummaryList(actualProjectIds); summaries.Add(new ProjectSummary()); var summaryCount = summaries.Count; for (int i = 0; i < summaryCount; i++) { var summary = (ProjectSummary)summaries[i]; summary.TrackedSeconds = i; } apiProjectsSummary.ProjectsSummaries.Returns(summaries); configureRepositoryToReturn(actualProjectIds); var report = ReportsProvider .GetProjectSummary(workspaceId, DateTimeOffset.Now.AddDays(-7), DateTimeOffset.Now).Wait(); report.Segments.Should().BeInDescendingOrder(s => s.Percentage); }
public async Task TracksAnEventWhenReportFailsToLoad() { var startDateRange = new DateTimeOffset(2018, 05, 05, 0, 0, 0, TimeSpan.Zero); var endDateRange = startDateRange.AddDays(7); var totalDays = (int)(endDateRange - startDateRange).TotalDays; var loadingDuration = TimeSpan.FromSeconds(5); var now = new DateTimeOffset(2018, 01, 01, 0, 0, 0, TimeSpan.Zero); TimeService.CurrentDateTime.Returns(_ => { now = now + loadingDuration; return(now); }); ReportsProvider.GetProjectSummary(Arg.Any <long>(), Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Throw <ProjectSummaryReport>(new Exception())); await Initialize(); AnalyticsService.Received().ReportsFailure.Track(ReportsSource.Initial, totalDays, loadingDuration.TotalMilliseconds); }
public async Task GroupsProjectSegmentsWithPercentageBetweenOneAndFiveIntoOtherIfTotalOfOtherLessThanFivePercent() { ChartSegment[] segments = { new ChartSegment("Project 1", "Client 1", 0.9f, 2, 0, "#ffffff"), new ChartSegment("Project 2", "Client 2", 0.9f, 3, 0, "#ffffff"), new ChartSegment("Project 3", "Client 3", 2.5f, 4, 0, "#ffffff"), new ChartSegment("Project 4", "Client 4", 4, 12, 0, "#ffffff"), new ChartSegment("Project 5", "Client 5", 31.7f, 23, 0, "#ffffff"), new ChartSegment("Project 6", "Client 6", 60, 56, 0, "#ffffff") }; TimeService.CurrentDateTime.Returns(new DateTimeOffset(2018, 05, 15, 12, 00, 00, TimeSpan.Zero)); ReportsProvider.GetProjectSummary(WorkspaceId, Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Return(new ProjectSummaryReport(segments, projectsNotSyncedCount))); var segmentsObservable = TestScheduler.CreateObserver <IReadOnlyList <ChartSegment> >(); var groupedSegmentsObservable = TestScheduler.CreateObserver <IReadOnlyList <ChartSegment> >(); ViewModel.SegmentsObservable.Subscribe(segmentsObservable); ViewModel.GroupedSegmentsObservable.Subscribe(groupedSegmentsObservable); TestScheduler.Start(); await Initialize(); var actualSegments = segmentsObservable.Values().Last(); var actualGroupedSegments = groupedSegmentsObservable.Values().Last(); actualSegments.Should().HaveCount(6); actualGroupedSegments.Should().HaveCount(4); actualGroupedSegments.Should().Contain(segment => segment.ProjectName == Resources.Other && segment.Percentage == segments[0].Percentage + segments[1].Percentage + segments[2].Percentage); actualGroupedSegments .Where(project => project.ProjectName != Resources.Other) .Select(segment => segment.Percentage) .ForEach(percentage => percentage.Should().BeGreaterOrEqualTo(4)); }
public async Task SetsOtherProjectWithOneSegmentToThatSegmentButWithOnePercentIfLessThanOnePercent() { ChartSegment[] segments = { new ChartSegment("Project 1", "Client 1", 0.2f, 2, 0, "#666666"), new ChartSegment("Project 2", "Client 2", 8.8f, 4, 0, "#ffffff"), new ChartSegment("Project 3", "Client 3", 12, 12, 0, "#ffffff"), new ChartSegment("Project 4", "Client 4", 23, 23, 0, "#ffffff"), new ChartSegment("Project 5", "Client 5", 56, 56, 0, "#ffffff") }; TimeService.CurrentDateTime.Returns(new DateTimeOffset(2018, 05, 15, 12, 00, 00, TimeSpan.Zero)); ReportsProvider.GetProjectSummary(WorkspaceId, Arg.Any <DateTimeOffset>(), Arg.Any <DateTimeOffset>()) .Returns(Observable.Return(new ProjectSummaryReport(segments, projectsNotSyncedCount))); var segmentsObservable = TestScheduler.CreateObserver <IReadOnlyList <ChartSegment> >(); var groupedSegmentsObservable = TestScheduler.CreateObserver <IReadOnlyList <ChartSegment> >(); ViewModel.SegmentsObservable.Subscribe(segmentsObservable); ViewModel.GroupedSegmentsObservable.Subscribe(groupedSegmentsObservable); TestScheduler.Start(); await Initialize(); var actualSegments = segmentsObservable.Values().Last(); var actualGroupedSegments = groupedSegmentsObservable.Values().Last(); actualSegments.Should().HaveCount(5); actualGroupedSegments.Should().HaveCount(5); actualGroupedSegments.Should().Contain(segment => segment.ProjectName == "Project 1" && segment.Percentage == 1f && segment.Color == "#666666"); actualGroupedSegments .Where(project => project.ProjectName != "Project 1") .Select(segment => segment.Percentage) .ForEach(percentage => percentage.Should().BeGreaterOrEqualTo(5)); }