在测试项目中运行所有测试时管理 Application.Current [英] Manage Application.Current while all tests are running in Test Project
问题描述
问题介绍
当测试的方法/函数包含 Dispatcher 用法时,此站点上有几个关于 Application.Current is null 问题的问题.我第一次只使用了一个简单的解决方案.我刚刚创建了一个 getter 属性来创建一个 new Application()
以防止Application.Current 为空问题".
There are several issues on this site about the Application.Current is null problem when a method/function of test contains Dispatcher usage. First time I just used a simple solution. I just made a getter property to create a new Application()
to prevent the "Application.Current is null problem".
问题的第一部分:
Application.Current null 问题已解决,但 Dispatcher.BeginInvoke 函数从未在 UI 线程上调用,并且此函数抛出 InvalidOperationException 并显示以下消息调用线程必须是STA 异常..."我无法理解,因为此异常通常由后台线程或任务抛出以及使用调度程序问题的解决方案.在此之后,我在运行测试之前使用了以下代码.
Application.Current null issue has been solved but Dispatcher.BeginInvoke function never called on UI thread and this function threw InvalidOperationException with the following message "The calling thread must be STA exception..." I could not understand because this exception usually throw by background thread or task and the solution to the problem of using dispatcher. After this I used the following code before run my tests.
第一个实现:(测试类中构造函数的一部分.)
First implementation: (A part of the constructor in the test class.)
var waitForApplicationRun = new TaskCompletionSource<bool>();
Thread t = new Thread(() =>
{
if(Application.Current == null)
new Application() { ShutdownMode = ShutdownMode.OnExplicitShutdown };
Application.Current.Startup += (s, e) => { waitForApplicationRun.SetResult(true); };
Application.Current.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
waitForApplicationRun.Task.Wait();
(这是代码片段的修改版本.)
(This is a modified version of a code snippet.)
我的测试方法在我的第一个测试类中毫无例外地使用了调度程序.
My test methods used the dispatcher without any exception in my first test class.
问题的第二部分:
我为我的睾丸创建了多个类,并将此代码片段移动到祖先类的构造函数中,因为我不想将此解决方案复制到每个测试类中.所以我为我的测试创建了一个具有通用设置的基类.当我尝试在测试项目中使用多个类运行所有测试时,我感到震惊,因为我预计测试行为不会改变,但 Application.Current 抛出 InvalidOperationException 并显示以下消息:调用线程无法访问此对象,因为其他线程拥有它."
I created multiple classes for my testes and I moved this code snippet to constructor of an ancestor class because i did not want to copy this solution into every test class. So I made a base class with common setup for my tests. When I tried to run all my tests with multiple classes in my test project, I was shocked because I expected that the tests behavior won't change but Application.Current threw InvalidOperationException with the following message: "The calling thread cannot access this object because a different thread owns it."
最后我用锁的用法解决了这个问题.我使用以下代码段扩展和修改了我的代码:
Finally I solved this problem with lock usage. I have extended and modified my code with the following snippet:
第二个实现:(基础测试类的一部分.)
Second implementation: (A part of the base test class.)
private Application getApplication
{
get
{
if (Application.Current == null) new Application() { ShutdownMode = ShutdownMode.OnExplicitShutdown };
return Application.Current;
}
}
private static object locker = new object();
public BaseTest()
{
Thread t = new Thread(() =>
{
lock (locker)
{
getApplication.Startup += (s, e) => Monitor.Pulse(locker);
getApplication.Run();
Monitor.Wait(locker);
}
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
在我的最后一个解决方案之后,所有类的测试(在测试项目中)都没有出现任何问题.
After my last solution all tests of classes (in test project) finished without any problem.
这是一个可以接受的解决方案还是它似乎隐藏了问题?
Is this an acceptable solution or it seems to hide the problem(s)?
推荐答案
在我看来,工作始终是任何代码的积极方面.一些团队采用不同的方法,避免使用调度程序.其他人在存根中使用调度程序的任何代码都可以使用 ioc 进行测试.MVVM 的优点之一是您可以实例化视图模型以进行测试,而无需实例化甚至模拟视图.一些纯粹主义者会说,如果您在视图模型中完全使用调度程序,那么您的视图依赖性就很糟糕.
Working is always a positive aspect of any code, in my opinion. Some teams take a different approach and use of dispatcher is avoided. Others have any code using dispatcher in a stub which can be switched out using ioc for tests. One of the advantages of MVVM is that you can instantiate a viewmodel for testing without instantiating or even mocking a view. Some purists would say if you use dispatcher at all in a viewmodel then you have a view dependency which is bad.
这篇关于在测试项目中运行所有测试时管理 Application.Current的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!