Chr*_*erd 48 .net c# wpf unit-testing dispatcher
我无法让Dispatcher运行委托我在单元测试时传递给它.当我运行程序时,一切正常,但是,在单元测试期间,以下代码将无法运行:
this.Dispatcher.BeginInvoke(new ThreadStart(delegate
{
this.Users.Clear();
foreach (User user in e.Results)
{
this.Users.Add(user);
}
}), DispatcherPriority.Normal, null);
Run Code Online (Sandbox Code Playgroud)
我在我的viewmodel基类中有这个代码来获取Dispatcher:
if (Application.Current != null)
{
this.Dispatcher = Application.Current.Dispatcher;
}
else
{
this.Dispatcher = Dispatcher.CurrentDispatcher;
}
Run Code Online (Sandbox Code Playgroud)
我是否需要做一些事情来初始化Dispatcher进行单元测试?Dispatcher永远不会在委托中运行代码.
jbe*_*jbe 87
通过使用Visual Studio单元测试框架,您无需自己初始化Dispatcher.您完全正确,Dispatcher不会自动处理其队列.
您可以编写一个简单的帮助方法"DispatcherUtil.DoEvents()",它告诉Dispatcher处理其队列.
C#代码:
public static class DispatcherUtil
{
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
private static object ExitFrame(object frame)
{
((DispatcherFrame)frame).Continue = false;
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
您也可以在WPF应用程序框架(WAF)中找到此类.
Ori*_*rds 21
我们通过简单地模拟接口后面的调度程序,并从IOC容器中提取接口来解决这个问题.这是界面:
public interface IDispatcher
{
void Dispatch( Delegate method, params object[] args );
}
Run Code Online (Sandbox Code Playgroud)
这是在真实应用程序的IOC容器中注册的具体实现
[Export(typeof(IDispatcher))]
public class ApplicationDispatcher : IDispatcher
{
public void Dispatch( Delegate method, params object[] args )
{ UnderlyingDispatcher.BeginInvoke(method, args); }
// -----
Dispatcher UnderlyingDispatcher
{
get
{
if( App.Current == null )
throw new InvalidOperationException("You must call this method from within a running WPF application!");
if( App.Current.Dispatcher == null )
throw new InvalidOperationException("You must call this method from within a running WPF application with an active dispatcher!");
return App.Current.Dispatcher;
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是我们在单元测试期间提供给代码的模拟代码:
public class MockDispatcher : IDispatcher
{
public void Dispatch(Delegate method, params object[] args)
{ method.DynamicInvoke(args); }
}
Run Code Online (Sandbox Code Playgroud)
我们还有一个MockDispatcher
在后台线程中执行委托的变体,但在大多数情况下它并不是必需的
Ste*_*cht 17
您可以使用调度程序进行单元测试,只需使用DispatcherFrame即可.下面是我的一个单元测试的示例,它使用DispatcherFrame强制调度程序队列执行.
[TestMethod]
public void DomainCollection_AddDomainObjectFromWorkerThread()
{
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
DispatcherFrame frame = new DispatcherFrame();
IDomainCollectionMetaData domainCollectionMetaData = this.GenerateIDomainCollectionMetaData();
IDomainObject parentDomainObject = MockRepository.GenerateMock<IDomainObject>();
DomainCollection sut = new DomainCollection(dispatcher, domainCollectionMetaData, parentDomainObject);
IDomainObject domainObject = MockRepository.GenerateMock<IDomainObject>();
sut.SetAsLoaded();
bool raisedCollectionChanged = false;
sut.ObservableCollection.CollectionChanged += delegate(object sender, NotifyCollectionChangedEventArgs e)
{
raisedCollectionChanged = true;
Assert.IsTrue(e.Action == NotifyCollectionChangedAction.Add, "The action was not add.");
Assert.IsTrue(e.NewStartingIndex == 0, "NewStartingIndex was not 0.");
Assert.IsTrue(e.NewItems[0] == domainObject, "NewItems not include added domain object.");
Assert.IsTrue(e.OldItems == null, "OldItems was not null.");
Assert.IsTrue(e.OldStartingIndex == -1, "OldStartingIndex was not -1.");
frame.Continue = false;
};
WorkerDelegate worker = new WorkerDelegate(delegate(DomainCollection domainCollection)
{
domainCollection.Add(domainObject);
});
IAsyncResult ar = worker.BeginInvoke(sut, null, null);
worker.EndInvoke(ar);
Dispatcher.PushFrame(frame);
Assert.IsTrue(raisedCollectionChanged, "CollectionChanged event not raised.");
}
Run Code Online (Sandbox Code Playgroud)
我在这里发现了它.
我通过在我的单元测试设置中创建一个新的应用程序解决了这个问题。
然后任何被测类访问 Application.Current.Dispatcher 都会找到一个调度程序。
因为 AppDomain 中只允许一个应用程序,所以我使用了 AssemblyInitialize 并将其放入自己的类 ApplicationInitializer 中。
[TestClass]
public class ApplicationInitializer
{
[AssemblyInitialize]
public static void AssemblyInitialize(TestContext context)
{
var waitForApplicationRun = new TaskCompletionSource<bool>()
Task.Run(() =>
{
var application = new Application();
application.Startup += (s, e) => { waitForApplicationRun.SetResult(true); };
application.Run();
});
waitForApplicationRun.Task.Wait();
}
[AssemblyCleanup]
public static void AssemblyCleanup()
{
Application.Current.Dispatcher.Invoke(Application.Current.Shutdown);
}
}
[TestClass]
public class MyTestClass
{
[TestMethod]
public void MyTestMethod()
{
// implementation can access Application.Current.Dispatcher
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
31693 次 |
最近记录: |