如何在 Xamarin Forms 视图模型中组织代码以进行单元测试?
How to organize code in Xamarin Forms viewmodel for unit testing?
我有一个使用 Mvvm Light 和 Ninject 的 XF 项目。
我正在尝试回溯并为我的视图模型编写单元测试,但我将 运行 保留在需要调用 Xamarin.Forms.Init() 或我引用 Device.BeginInvokeOnMainThread 或其他 [=31= 的问题中] RelayCommands 中的特定内容。
所以典型的 RelayCommand 可能如下所示:
public RelayCommand DeleteGameCommand
{
get
{
return _deleteGameCommand
?? (_deleteGameCommand = new RelayCommand(
async () =>
{
Device.BeginInvokeOnMainThread(() => ToggleMasterMenuDisplayCommand.Execute(null));
var response = await
((MasterDetailPage) Application.Current.MainPage).Detail.DisplayActionSheet("Are you sure?", "Cancel",
"Delete Game");
if (response == "Delete Game")
{
StopTimer();
using (new Busy(this, "Deleting Game..."))
{
await GameService.DeleteGame(Game, true);
await AzureService.SyncGameInfoForGame(Game.GameId, true);
}
App.Current.Container.Get<DashboardViewModel>().ShouldRefreshDataOnNextDisplay();
Device.BeginInvokeOnMainThread(() =>
{
App.Current.HideLoading();
LoadHomeAsMainPage();
});
}
}));
}
}
Busy() 调用一些 UI 东西来显示进度指示器。
App.Current.Container 是我的 Ninject 内核。
我是否应该将其重构为更类似的东西:
public RelayCommand DeleteGameCommand
{
get
{
return _deleteGameCommand
?? (_deleteGameCommand = new RelayCommand(
async () =>
{
Device.BeginInvokeOnMainThread(() => ToggleMasterMenuDisplayCommand.Execute(null));
var response = await
((MasterDetailPage) Application.Current.MainPage).Detail.DisplayActionSheet("Are you sure?", "Cancel",
"Delete Game");
if (response == "Delete Game")
{
StopTimer();
using (new Busy(this, "Deleting Game..."))
{
await BusinessLogic.DeleteGame(Game,true);
}
App.Current.Container.Get<DashboardViewModel>().ShouldRefreshDataOnNextDisplay();
Device.BeginInvokeOnMainThread(() =>
{
App.Current.HideLoading();
LoadHomeAsMainPage();
});
}
}));
}
}
public class BusinessLogic
{
public async Task DeleteGame(Game game, bool includeRelated)
{
await GameService.DeleteGame(game, true);
await AzureService.SyncGameInfoForGame(game.GameId, true);
}
}
我意识到这可能不是最好的例子,因为这两个服务调用很可能已经过单元测试,但在其他中继命令中,除了调用服务之外还有更多的事情要做。
我在想,如果我做这样的事情,那么我就可以对所有业务逻辑进行单元测试,而永远不会编写调用 RelayCommand 的测试。
我不确定其他人是如何进行单元测试视图模型的,我能找到的大部分信息都有非常简单的示例,它们从来没有解决我 运行 关注的问题。
通常您会创建并调用包装器,这样当您进行自动化测试时,这些存根就会 运行 代替。您模拟的 Init 和 BeginInvokeOnMainThread 可能会转发到不同的实现。
我有一个使用 Mvvm Light 和 Ninject 的 XF 项目。 我正在尝试回溯并为我的视图模型编写单元测试,但我将 运行 保留在需要调用 Xamarin.Forms.Init() 或我引用 Device.BeginInvokeOnMainThread 或其他 [=31= 的问题中] RelayCommands 中的特定内容。
所以典型的 RelayCommand 可能如下所示:
public RelayCommand DeleteGameCommand
{
get
{
return _deleteGameCommand
?? (_deleteGameCommand = new RelayCommand(
async () =>
{
Device.BeginInvokeOnMainThread(() => ToggleMasterMenuDisplayCommand.Execute(null));
var response = await
((MasterDetailPage) Application.Current.MainPage).Detail.DisplayActionSheet("Are you sure?", "Cancel",
"Delete Game");
if (response == "Delete Game")
{
StopTimer();
using (new Busy(this, "Deleting Game..."))
{
await GameService.DeleteGame(Game, true);
await AzureService.SyncGameInfoForGame(Game.GameId, true);
}
App.Current.Container.Get<DashboardViewModel>().ShouldRefreshDataOnNextDisplay();
Device.BeginInvokeOnMainThread(() =>
{
App.Current.HideLoading();
LoadHomeAsMainPage();
});
}
}));
}
}
Busy() 调用一些 UI 东西来显示进度指示器。 App.Current.Container 是我的 Ninject 内核。
我是否应该将其重构为更类似的东西:
public RelayCommand DeleteGameCommand
{
get
{
return _deleteGameCommand
?? (_deleteGameCommand = new RelayCommand(
async () =>
{
Device.BeginInvokeOnMainThread(() => ToggleMasterMenuDisplayCommand.Execute(null));
var response = await
((MasterDetailPage) Application.Current.MainPage).Detail.DisplayActionSheet("Are you sure?", "Cancel",
"Delete Game");
if (response == "Delete Game")
{
StopTimer();
using (new Busy(this, "Deleting Game..."))
{
await BusinessLogic.DeleteGame(Game,true);
}
App.Current.Container.Get<DashboardViewModel>().ShouldRefreshDataOnNextDisplay();
Device.BeginInvokeOnMainThread(() =>
{
App.Current.HideLoading();
LoadHomeAsMainPage();
});
}
}));
}
}
public class BusinessLogic
{
public async Task DeleteGame(Game game, bool includeRelated)
{
await GameService.DeleteGame(game, true);
await AzureService.SyncGameInfoForGame(game.GameId, true);
}
}
我意识到这可能不是最好的例子,因为这两个服务调用很可能已经过单元测试,但在其他中继命令中,除了调用服务之外还有更多的事情要做。
我在想,如果我做这样的事情,那么我就可以对所有业务逻辑进行单元测试,而永远不会编写调用 RelayCommand 的测试。
我不确定其他人是如何进行单元测试视图模型的,我能找到的大部分信息都有非常简单的示例,它们从来没有解决我 运行 关注的问题。
通常您会创建并调用包装器,这样当您进行自动化测试时,这些存根就会 运行 代替。您模拟的 Init 和 BeginInvokeOnMainThread 可能会转发到不同的实现。