Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么这个单元测试在我的机器上通过了,但在构建服务器上失败了?_C#_Wpf_Unit Testing_Mvvm_Mstest - Fatal编程技术网

C# 为什么这个单元测试在我的机器上通过了,但在构建服务器上失败了?

C# 为什么这个单元测试在我的机器上通过了,但在构建服务器上失败了?,c#,wpf,unit-testing,mvvm,mstest,C#,Wpf,Unit Testing,Mvvm,Mstest,我正在使用VS2010,用MSTest编写单元测试。我的项目使用WPF、MVVM和PRISM框架。我还使用Moq来模拟接口 我正在测试命令和列表中选定项之间的交互。根据MVVM模式,交互被封装在ViewModel中。基本上,当设置SelectedDatabase时,我希望命令引发CanExecute。我为以下行为编写了此测试: 公共无效测试() { var databaseService=new Mock(); var databasefunctionscoontroller=new Mock(

我正在使用VS2010,用MSTest编写单元测试。我的项目使用WPF、MVVM和PRISM框架。我还使用Moq来模拟接口

我正在测试命令和列表中选定项之间的交互。根据MVVM模式,交互被封装在ViewModel中。基本上,当设置SelectedDatabase时,我希望命令引发CanExecute。我为以下行为编写了此测试:

公共无效测试()
{
var databaseService=new Mock();
var databasefunctionscoontroller=new Mock();
//创建视图模型
OpenDatabaseViewModel视图模型
=新的OpenDatabaseViewModel(databaseService.Object、databaseFunctionsController.Object);
//模拟数据库及其视图模型
var database=TestHelpers.HelpGetMockIDatabase();
var databaseViewModel=新的databaseViewModel(database.Object);
//连接可以执行更改的事件
var resetEvent=新的自动重置事件(false);
bool canExecuteChanged=false;
viewModel.OpenDatabaseCommand.CanExecuteChanged+=(s,e)=>
{
resetEvent.Set();
canExecuteChanged=真;
};
//设置所选数据库
viewModel.SelectedDatabase=数据库viewModel;
//允许事件发生
resetEvent.WaitOne(250);
//检查它是否有效
Assert.IsTrue(canExecuteChanged,
“设置SelectedDatabase时应引发OpenDatabaseCommand.CanExecuteChanged”);
}
OpenDatabaseViewModel
上,
SelectDatabase
属性如下:

公共数据库视图模型选择数据库 { 获取{return\u selectedDatabase;} 设置 { _selectedDatabase=值; RaisePropertyChanged(“SelectedDatabase”); //根据保存更新can execute标志 ((DelegateCommand)OpenDatabaseCommand).raiseCancecutechanged(); } } 以及在viewmodel上:

bool OpenDatabaseCanExecute()
{
返回_selectedDatabase!=null;
}
TestHelpers.HelpGetMockIDatabase()
只获取一个设置了一些属性的模拟
IDatabase

当我从VS2010运行测试时,该测试通过,但在服务器上作为自动构建的一部分执行时失败。我输入了
AutoResetEvent
试图解决这个问题,但没有效果

我发现自动测试使用的是MSTest命令行中的
noisolation
标志,所以我删除了它。然而,这产生了一次“通过”,但下一次“失败”

我想我在这一切中遗漏了一些重要的东西,但我不知道它是什么。有人能告诉我我做错了什么吗?

剩下的代码可能失败的地方只有
SelectedDatabase
属性代码段中的这两行

        RaisePropertyChanged("SelectedDatabase");
        // Update the can execute flag based on the save
        ((DelegateCommand)OpenDatabaseCommand).RaiseCanExecuteChanged();
还有一些人在
RaisePropertyChanged()
和它的魔法字符串使用方面有一些问题;但这可能不是你眼前的问题。尽管如此,如果您想继续删除魔法字符串依赖项,可以查看这些链接


raisecancecutechanged()
方法是另一个可疑的方法,在PRISM中查找文档会发现此方法希望在UI线程上分派事件。从mstest来看,不能保证UI线程用于分派测试

我建议您在其周围添加一个try/catch块,并查看调用
raisecancecutechanged()
时是否引发任何异常。请注意抛出的异常,以便您可以决定下一步如何继续。如果你绝对需要测试这个事件分派,你可以考虑编写一个小的WPF意识的应用程序(或者控制台应用程序)来运行实际的测试和退出,并让你的测试启动那个应用程序来观察结果。这将使您的测试与任何或您的生成服务器隔离

起初的 这段代码似乎可疑。如果您的事件从另一个线程触发,则原始线程可能会在分配之前首先退出等待,从而导致您的标志被读取为过时值

viewModel.OpenDatabaseCommand.CanExecuteChanged += (s, e) =>
    {
         resetEvent.Set();
         canExecuteChanged = true;
    };
考虑将块中的行重新排序为:

viewModel.OpenDatabaseCommand.CanExecuteChanged += (s, e) =>
    {
         canExecuteChanged = true;
         resetEvent.Set();
    };
另一个问题是,您没有检查等待是否满足。如果在没有信号的情况下250毫秒过去了,您的标志将为假

请参阅以检查将接收哪些返回值,并更新这段代码以处理未签名退出的情况

// Allow the event to happen
resetEvent.WaitOne(250);

// Check that it worked
Assert.IsTrue(canExecuteChanged,
    "OpenDatabaseCommand.CanExecuteChanged should be raised when SelectedDatabase is set");

我已经找到了一个答案来解释这个单元测试到底发生了什么。还有其他复杂的因素,我当时没有意识到这一点。我在最初的问题中没有包括这些细节,因为我认为它们不相关

代码问题中描述的视图模型是使用WinForms集成的项目的一部分。作为一个孩子,我正在托管一个棱镜壳。在回答有关stackoverflow的问题后,添加此选项以创建适当的
应用程序。当前

公共类MyApp:System.Windows.Application
{
}
if(System.Windows.Application.Current==null)
{
//创建应用程序对象
新MyApp();
}
上述代码不是由所讨论的单元测试执行的。但是,它在其他预先运行的单元测试中被使用,并且所有的单元测试都使用MSTest.exe的
/noisolation
标志一起运行

这有什么关系?好吧,埋在PRISM代码中,作为

((DelegateCommand)OpenDatabaseCommand).raisecancecutechanged();
在内部类
Microsoft.Practices.Prism.Commands.WeakEventHandler
中,此方法是:

publicstaticdispatcherproxy CreateDispatcher()
{
DispatcherProxy proxy=null;
#如果是