当前位置: 首页 > 编程语言 > C#

如何让WebBrowser在headless单元测试中运行时完成导航?分享

时间:2023-04-10 22:27:18 C#

WebBrowser运行headless单元测试时如何实现完整导航?我们有一个WPF应用程序,它在控件中加载一些内容,然后根据加载的内容进行一些调用。有了正确的模拟,我们认为我们可以在一个没有出现的单元测试中进行测试(在这种情况下是NUnit)。但是WebBrowser控件不想玩好。问题是我们永远不会收到LoadCompleted或Navigated事件。显然这是因为网页在实际呈现之前从未“加载”(请参阅??此MSDN线程)。我们确实收到了Navigating事件,但对我们来说还为时过早。那么有没有一种方法可以使WebBrowser控件“完全”工作,即使它没有要显示的输出?这是测试用例的简化版本:[TestFixture,RequiresSTA]classTestIsoView{[Test]publicvoidPageLoadsAtAll(){Console.WriteLine("I'malumberjackandI'mOK");WebBrowserwb=newWebBrowser();//AutoResetEvent允许我们同步等待事件发生。AutoResetEventautoResetEvent=newAutoResetEvent(false);//wb.LoadCompleted+=delegate//LoadCompleted从未收到wb.Navigated+=delegate//Navigated从未收到//wb.Navigating+=delegate//Navigating*is*received{//除非我们等待wb.NavigatingConsole.WriteLine("文档已加载!!");autoResetEvent.Set();};Console.WriteLine("注册信号处理器","Navigating");wb.NavigateToString("这里是戏剧");Console.WriteLine("异步导航开始!等待ARE");autoResetEvent.WaitOne();//在到达这里之前测试挂起。Console.WriteLine("知道了!");您需要使用消息循环分离STA线程。您将在该线程上创建WebBrowser实例并抑制脚本错误。请注意,WPFWebBrowser对象需要实时主机窗口才能运行。这就是它与WinFormsWebBrowser的不同之处。以下是如何完成此操作的示例:staticasyncTaskRunWpfWebBrowserAsync(stringurl){//通过Task返回结果varresultTcs=newTaskCompletionSource();//要在STA线程上执行的主要WPFWebBrowser驱动逻辑Actionstartup=async()=>{try{//创建主机窗口varhostWindow=newWindow();hostWindow.ShowActivated=false;hostWindow.ShowInTaskbar=false;hostWindow.Visibility=Visibility.Hidden;hostWindow.Show();//创建一个WPFWebBrowser实例varwb=newWebBrowser();hostWindow.Content=wb;//抑制脚本错误:https://stackoverflow.com/a/18289217//触摸wb.Document确保已创建底层ActiveXdynamicdocument=wb.Document;动态activeX=wb.GetType().InvokeMember("ActiveXInstance",BindingFlags.GetProperty|BindingFlags.Instance|BindingFlags.NonPublic,null,wb,newobject[]{});activeX.Silent=true;//导航并处理LoadCompletedvarnavigationTcs=newTaskCompletionSource();wb.LoadCompleted+=(s,e)=>navigationTcs.TrySetResult(true);wb.Navigate(url);等待导航Tcs.Task;//执行WebBrowser自动化document=wb.Document;//...//返回内容(例如)stringcontent=document.body.outerHTML;resultTcs.SetResult(内容);}catch(Exceptionex){//将异常传播给RunWpfWebBrowserAsync的调用者resultTcs.SetException(ex);}//结束:Dispatcher.Run()中的消息循环将退出Dispatcher.ExitAllFrames();};//线程过程ThreadStartthreadStart=()=>{//发布启动回调//它将在消息循环泵送时调用Dispatcher.CurrentDispatcher.BeginInvoke(startup);//运行WPFDispatcher消息循环Dispatcher.Run();调试断言(真);};//启动并运行STA线程varthread=newThread(threadStart);thread.SetApartmentState(ApartmentState.STA);线程。开始();try{//使用Task.ConfigureAwait(false)来避免dUI线程上的死锁//如果调用者执行阻塞调用,即://"RunWpfWebBrowserAsync(url).Wait()"或//"RunWpfWebBrowserAsync(url).Result"returnawaitresultTcs.Task.ConfigureAwait(false);}finally{//确保线程已经完全结束thread.Join();}}Usage://阻塞调用stringcontent=RunWpfWebBrowserAsync("http://www.example.com").Result;//asynccallstringcontent=awaitRunWpfWebBrowserAsync("http://www.example.org")您也可以尝试直接在NUnit线程上运行threadStartlambda而无需实际创建新线程这样NUnit线程将运行Dispatcher消息循环。我对NUnit不够熟悉,无法预测它是否会起作用。如果您不想创建宿主窗口,请考虑使用WinFormsWebBrowser。我在控制台应用程序中发布了一个类似的独立示例。不确定它是否有效,但如果您使用像Moq这样的模拟框架,您可以将“IsLoaded”属性模拟为“true”并欺骗WebBrowser加载。当然,如果WebBrowser实际上需要一个完全可用的显示器,我也不会感到惊讶。许多html、javascript和dom都依赖于屏幕测量和事件。以上是C#学习教程:HowtomakeWebBrowserrunninginaheadlessunittest时完成导航?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: