我使用 xUnit 和 Moq 。
在我的 MainViewModel 类中,我有一个由两个命令调用的方法。该方法更新了几个属性: `
public void CommandCompletedControlsSetup()
{
//TokenSource.Dispose();
UpdateStatusBar = 0;
VisibilityStatusBar = Visibility.Hidden;
ValidateButtons();
ProgressDisplay = "";
WorkStatus = "";
VisibilityCancellingMsg = Visibility.Visible;
VisibilityCancelTestingBtn = Visibility.Collapsed;
VisibilityTestingBtn = Visibility.Visible;
VisibilityCancelUpdatingBtn = Visibility.Collapsed;
VisibilityUpdatingBtn = Visibility.Visible;
}
我只是想避免为每个命令测试整个方法的更新。第一次执行命令:
public void OnUpdateCancellationExecute(object obj)
{
_updateDataService.CancelUpdates();
CommandCompletedControlsSetup(); // here is method call
}
第二条命令执行:
public void OnSimulateCancellationExecute(object obj)
{
_simulateDataService.CancelSimulation();
CommandCompletedControlsSetup(); // here is method call
}
因此不必重复两次:
[Fact]
public void OnSimulateCancellationExecute_UpdatesViewProps_True()
{
_viewModel.UpdateStatusBar = 1000;
_viewModel.VisibilityStatusBar = Visibility.Visible;
_viewModel.ProgressDisplay = "1000/1000";
_viewModel.WorkStatus = "some status";
_viewModel.VisibilityCancellingMsg = Visibility.Hidden;
_viewModel.VisibilityCancelTestingBtn = Visibility.Visible;
_viewModel.VisibilityTestingBtn = Visibility.Hidden;
_viewModel.VisibilityCancelUpdatingBtn = Visibility.Visible;
_viewModel.VisibilityUpdatingBtn = Visibility.Hidden;
_viewModel.SimulateCancellationCommand.Execute(null);
Assert.Equal(0, _viewModel.UpdateStatusBar);
Assert.Equal(Visibility.Hidden, _viewModel.VisibilityStatusBar);
Assert.Equal("", _viewModel.ProgressDisplay);
Assert.Equal("", _viewModel.WorkStatus);
Assert.Equal(Visibility.Visible, _viewModel.VisibilityCancellingMsg);
Assert.Equal(Visibility.Collapsed, _viewModel.VisibilityCancelTestingBtn);
Assert.Equal(Visibility.Visible, _viewModel.VisibilityTestingBtn);
Assert.Equal(Visibility.Collapsed, _viewModel.VisibilityCancelUpdatingBtn);
Assert.Equal(Visibility.Visible, _viewModel.VisibilityUpdatingBtn);
}
我想做这样的事情:
[Fact]
public void CancellationExecuteMethods_UpdatesViewProps_True()
{
_viewModel.SimulateCancellationCommand.Execute(null);
_viewModel.UpdateCancellationCommand.Execute(null);
//MainViewModel does not contain definition for Verify - exception
_viewModel.Verify(sd => sd.CancelUpdates(), Times.Exactly(2));
}
但是 MainViewModel 没有被模拟,我不确定是否能够模拟它?如果是,那怎么办?如果没有,是否有其他方法可以测试是否调用了VM方法?还是我应该将其保留为显而易见的东西,然后单独测试该方法?
答案 0 :(得分:1)
嘲笑和依赖倒置原则是相辅相成的。如果要模拟某些东西,则需要“反转”模拟目标的依赖关系,以便可以用实际的模拟对象实例替换具体的实现。在您的具体示例中,您需要将CommandCompletedControlsSetup()
提取到一个单独的类中,然后使用构造函数注入将其传递给视图模型。由于视图模型需要无参数的构造函数才能在XAML中实例化它,因此这将导致应用程序启动发生重大变化。我不知道您现在是如何做的,但是您需要引导您的应用程序,并让您的DI容器创建视图实例并手动显示。
您还有另一个选择,就是不使用此命令,而不必显式测试它们。您的命令由一组方法组成。一种方法很精确(另一种方法是CommandCompletedControlsSetup()
,而您不想测试)。
在两个示例中,您的命令均调用服务类的公共方法:
updateDataService.CancelUpdates();
和_simulateDataService.CancelSimulation();
。
因此,您可能已经测试了此服务。如果不是,您可以或应该对其进行测试。如果您测试了这些服务,您还将隐式测试视图模型命令,因为它们依赖于那些服务。这样,您就可以绕过CommandCompletedControlsSetup()
。
但是,通常,您要模拟的每种行为都是您要测试的类型的一部分,必须将其注入该类型。
作为旁注,我个人更喜欢使用转换器将控件的可见性绑定到视图模型公开的布尔属性。您可以使用.NET框架提供的BooleanToVisibilityConverter
转换器。这样,我就避免引用来查看相关程序集。