我有一个用C#(.NET 4.0)编写的复杂WPF项目,我为(NUnit)编写了几个测试。这些测试存在于不同的类中,只要我为每个类单独运行测试,一切都很好。但是,一旦我尝试同时运行所有类的所有测试,第一个类的测试成功,但是一旦testrunner(Resharper或nunit-console)开始测试剩余的类,所有这些类都会失败,并显示以下堆栈跟踪。 / p>
System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it
at System.Windows.Threading.Dispatcher.VerifyAccess()
at System.Windows.Media.Imaging.BitmapDecoder.ToString()
at System.Windows.Media.Imaging.BitmapFrameDecode.ConvertToString(String format, IFormatProvider provider)
at System.Windows.Media.ImageSource.ToString()
at MUSTANG.ShowCase.ResourceLibrary.ResourceDictionaryManager.GetUriString(String pKey) in c:\Daten\Jenkins-ci\jobs\MUSTANG-Showcase-Release-VS2010\workspace\MUSTANG-Showcase\MUSTANG.ShowCase.ResourceLibrary\ResourceDictionaryManager.cs:Zeile 49.
相应的代码如下:
public object GetValue(string pKey)
{
if (mDictionary.Contains(pKey))
{
return mDictionary[pKey];
}
return null;
}
public String GetUriString(string pKey)
{
object result = GetValue(pKey);
if (null == result)
{
Log.Warn(string.Format(@"Ressource '{0}' nicht gefunden!", pKey));
return "";
}
return result.ToString();
}
当资源是图像时,GetUriString中的最后一行发生异常。 Nunit似乎使用不同的线程来运行不同的测试类 - 它们仍按顺序运行。有没有办法解决这个问题,例如通过告诉NUnit或testrunners使用单个线程,在每个测试类运行或类似之后完全退出?
编辑1:到目前为止我尝试了什么:
[RequiresSTA]
属性问题似乎是NUnit为每个包含测试方法的类使用不同的线程,所以我要么找到一种方法
OR
new Application();
答案 0 :(得分:7)
从堆栈跟踪中,您发布了一个“线程关联”问题 - 即您正在尝试更新与其创建的线程不同的线程上的UI元素。 BitmapDecoder派生自DispatcherObject,即它需要在单个线程上运行。在您的测试运行中,它似乎是在一个线程上创建的,然后方法调用(ToString)是从不同的线程创建的。
MUSTANG.ShowCase.ResourceLibrary
实例?如何为每个测试创建一个新实例,即隔离测试?更新:我想我现在已经确定了它。
[assembly: RequiresThread(ApartmentState.STA)]
答案 1 :(得分:1)
好的,我现在通过NUnit控制台运行带有/runlist
参数的测试(例如C:\NUnit-2.6.0.12051\bin\nunit-console-x86.exe My.Assembly.dll /xml=result.xml /runlist=..\testlist.txt
)来解决它,其中testlist.txt
包含我所有测试类的完全限定名称。这样NUnit似乎完全重启了每个要测试的类的应用程序。这个方法的缺点是,我必须添加到这个列表,一旦我添加一个新的测试类,但是现在,这个解决方案对我来说很好。
答案 2 :(得分:0)
尝试将RequiresSTA
属性添加到测试夹具中。见这里:http://www.nunit.org/index.php?p=requiresSTA&r=2.5.9
还有RequiresThread
和RequiresMTA
(多线程)属性,链接自同一篇文章。它可能无法解决您的问题,但听起来应该是这样。
答案 3 :(得分:0)
一种选择是确保Freeze
中ImageSource
个ResourceDictionary
个对象。如果Freezable
(例如ImageSource
)被冻结,则可以从多个线程访问它,但是不可修改。