C# 单元测试I命令和方法
我已经开发了一个使用MVVM作为体系结构的WPF应用程序,并且正在编写一些单元测试作为其中的一部分。在我的视图中,有一个按钮绑定到ViewModel中的属性,如下所示 视图模型C# 单元测试I命令和方法,c#,wpf,unit-testing,mvvm,icommand,C#,Wpf,Unit Testing,Mvvm,Icommand,我已经开发了一个使用MVVM作为体系结构的WPF应用程序,并且正在编写一些单元测试作为其中的一部分。在我的视图中,有一个按钮绑定到ViewModel中的属性,如下所示 视图模型 public ICommand MoreInfoCommand { get { if (_moreInfoCommand == null) { _moreInfoCommand = new RelayCommand(parameter =>
public ICommand MoreInfoCommand
{
get
{
if (_moreInfoCommand == null)
{
_moreInfoCommand = new RelayCommand(parameter => OpenLink());
}
return _moreInfoCommand;
}
}
private void OpenLink()
{
try
{
Process.Start("https://www.google.com/");
}
catch
{
// catch error...
}
}
在我的单元测试中,我创建了以下单元测试:
单元测试
[Description("Test MoreInfoCommand")]
[TestMethod]
public void TestMoreInfoCommand()
{
viewModel vm = new viewModel();
Assert.IsTrue(vm.MoreInfoCommand.CanExecute(null));
}
目前,这将测试属性,以查看在UI中单击按钮时是否可以执行相关方法。这会随着条件的满足而通过,但据我所知,我也需要测试功能。考虑到这一点,我应该如何做,例如,测试在单击按钮时是否出现正确的功能。即,如何测试在UI中单击按钮后执行ICommand MoreInfoCommand时发生的情况
我知道可以直接测试私有方法,但是在我的单元测试中,我也应该检查功能,如果是的话,我怎么做呢
提前感谢。您的视图模型实际上不可测试。如果希望这样做,应将对静态
过程的调用替换为对注入视图模型的接口的方法的调用
public ViewModel(IProcessLoader processLoader) =>
_processLoader = processLoader;
//...
private void OpenLink()
{
try
{
_processLoader.Start("https://www.google.com/");
}
catch
{
// catch error...
}
}
然后,您可以在单元测试中模拟接口,例如使用模拟框架,如:
重要的是要认识到,您应该只验证是否从视图模型调用了该方法。针对视图模型类的单元测试不应测试流程
类的功能。调用Start
时,视图模型的责任终止
.NET和底层操作系统负责进程
类的实际功能。您不应该只测试您自己的代码。vm.moreinformCommand.CanExecute(null)
只会在RelayCommand
中调用CanExecute
方法,但您没有提供任何CanExecute
对OpenLink
是否会成功执行没有任何说明
虽然我不是单元测试专家,但如果您的代码看起来像这样,我怀疑是否值得首先为它编写一个单元测试,因为它非常简单
正如用户auburg的评论所述,您可以检查流程是否启动,尽管流程的名称取决于哪个浏览器是标准浏览器。此外,您还必须等待一段时间才能开始该过程。也许有一个同名的进程已经在运行了,有很多麻烦
如果您真的愿意,您可以检查一个著名的模拟框架,例如Moq或Rhino mock,是否能够模拟流程。开始。在您的情况下,您的命令会生成一个流程,因此您的单元测试可以检查流程是否正在运行?我如何在单元测试中检查流程是否正在运行?您不知道。您应该验证该方法是否仅被调用。这就是您正在测试的视图模型的职责范围。请参阅我的答案,以了解如何解决此问题的示例。您需要模拟对静态方法的调用。@Anonymous:这能回答您的问题吗?
[TestMethod]
public void TestMoreInfoCommand()
{
//Arrange
Mock<IProcessLoader> processLoader = new Mock<IProcessLoader>();
viewModel vm = new viewModel(processLoader.Object);
ICommand command = vm.MoreInfoCommand;
//Act
command.Execute(null);
//Assert
processLoader.Verify(x => x.Start(It.IsAny<string>()));
}
public interface IProcessLoader
{
void Start(string s);
}
public class ProcessLoader : IProcessLoader
{
public void Start(string s) => Process.Start(s);
}