当前位置: 首页 > Web前端 > HTML5

Angular应用级依赖Fake

时间:2023-04-05 22:00:14 HTML5

原文:FakingdependenciesinAngularapplications利用Angular依赖注入系统的强大功能,我们可以伪造特定的用例。这对于自动化测试很有用,但在本文中,我们将研究一种将其用于手动测试的方法。为了让我们的生活更轻松,我们将创建一个浏览器假组件,由于自定义结构指令,该组件仅在开发模式下启用。只是为了好玩,我们将添加文本管道以在我们的组件模板中使用常见的字符串操作。模拟浏览器环境使用基于类的服务动态替换依赖项用户代理令牌工厂只对每个模块注入器评估一次,如果它没有被祖先组件或指令提供的元素注入器替换,我们必须使用另一种技术来假依赖。我们将用基于类的服务依赖替换依赖注入令牌依赖。//internet-explorer-11-banner.component.tsimport{Component}from'@angular/core';import{InternetExplorerService}from'./internet-explorer.service';@Component({selector:'internet-explorer-11-banner',templateUrl:'./internet-explorer-11-banner.component.html',})exportclassInternetExplorer11BannerComponent{privateisDismissed=false;得到isBannerVisible(){返回this.internetExplorer.isInternetExplorer11State&&!this.isDismissed;}constructor(privateinternetExplorer:InternetExplorerService,){}onDismiss(){this.isDismissed=true;}}//internet-explorer-service.tsimport{Inject,Injectable}from'@angular/core';import{userAgentToken}from'./user-agent.token';@Injectable({providedIn:'root',})exportclassInternetExplorerService{getisInternetExplorer11State():boolean{returnthis.isInternetExplorer11(this.userAgent);}构造函数(@Inject(userAgentToken)私人用户代理:海峡ing,){}isInternetExplorer11(userAgent:string):boolean{return/Trident\/7\.0.+rv:11\.0/.test(userAgent);}首先,我们从依赖项注入令牌中提取InternetExplorer11检测我们新创建的InternetExplorerService类InternetExplorerService检测令牌现在在针对用户代理评估它们的值时委托给服务。如前所述,我们不使用元素注入器在模板中以声明方式动态替换用户代理标记。相反,我们将强制改变状态。创建一个可观察状态下面展示的方法并没有使用userAgenttoken的注入token,而是使用了Observable。这个Observable对象是从另一个浏览器服务中获得的。//internet-explorer.service.tsimport{Injectable}from'@angular/core';import{Observable}from'rxjs';import{map}from'rxjs/operators';import{BrowserService}from'./browser.service';@Injectable({providedIn:'root',})exportclassInternetExplorerService{isInternetExplorer11$:Observable=this.browser.userAgent$.pipe(map(userAgent=>this.isInternetExplorer11(userAgent)),);构造函数(私有浏览器:BrowserService,){}isInternetExplorer11(userAgent:string):boolean{return/Trident\/7\.0.+rv:11\.0/.test(userAgent);}}浏览器服务实现里,还是会使用用户代理注入令牌://browser.service.tsimport{Inject,Injectable,OnDestroy}from'@angular/core';import{BehaviorSubject}from'rxjs';import{distinctUntilChanged}从'rxjs/operators';从'./fake-user-agent'导入{FakeUserAgent};从'./user-agent.token'导入{userAgentToken};@Injectable({providedIn:'root',})exportclassBrowserServiceimplementsOnDestroy{//这体现了Observable和BehaviorSubject的区别:后者在实例化时,需要一个初始值:privateuserAgent=newBehaviorSubject(this.realUserAgent);userAgent$=this.userAgent.pipe(distinctUntilChanged(),);constructor(@Inject(userAgentToken)privaterealUserAgent:string,){}ngOnDestroy(){this.userAgent.complete();}fakeUserAgent(value:FakeUserAgent){this.userAgent.next(FakeUserAgent[value]);}stopFakingUserAgent(){this.userAgent.next(this.realUserAgent);我们将当前用户代理状态存储在BehaviorSubject中,当整个应用程序需要用户代理时,它在BrowserService可观察的userAgent$属性中公开,它应该依赖于这个可观察的。最初,行为主体的初始值来自用户代理令牌的真实用户代理字符串。这个值也被存储以供以后使用,因为我们允许使用两个命令更改浏览器状态。我们公开了fakeUserAgent方法,该方法将用户代理状态设置为虚假的用户代理字符串。此外,我们允许依赖者调用stopFakingUserAgent方法,该方法将用户代理状态重置为真正的用户代理字符串。InternetExplorer服务现在公开一个名为isInternetExplorer11$的可观察属性,只要浏览器服务的可观察用户代理属性发出值,就会对该属性进行求值。InternetExplorer服务现在公开一个名为isInternetExplorer11$的可观察属性,只要浏览器服务的可观察用户代理属性发出值,就会对其求值。我们现在需要做的就是让已弃用的横幅组件依赖于可观察到的InternetExplorer11检测属性,而不是我们替换的常规属性。抱歉,我们将不再支持InternetExplorer11。
请升级到MicrosoftEdge.
Dismiss现在的横幅是否可见,是由两个boolean值控制了,所以使用combineLatest.//internet-explorer-11-banner.component.tsimport{Component}from'@angular/core';import{BehaviorSubject,combineLatest}from'rxjs';import{map}from'rxjs/operators';import{InternetExplorerService}from'./internet-explorer.service';@Component({host:{style:'display:block;'},selector:'internet-explorer-11-banner',templateUrl:'./internet-explorer-11-banner.component.html',})导出类InternetExplorer11BannerComponent{privateisDismissed=newBehaviorSubject(false);isBannerVisible$=combineLatest(this.internetExplorer.isInternetExplorer11$,this.isDismissed,).pipe(map(([isInternetExplorer11,isDismissed])=>isInternetExplorer11&&!isDismissed),);构造函数(私有internetExplorer:InternetExplorerService,){}onDismiss():void{this.isDismissed.next(真);在弃用的横幅组件中,我们用最初清除(设置为false)的BehaviorSubject替换了BooleanisDismissed属性。$。UI行为逻辑与之前类似,不同之处在于它现在表示为可观察管道的一部分。现在,onDismiss事件处理程序不是为属性分配一个布尔值,而是通过isDismissed操作主体发出一个布尔值。此时,应用程序的行为与我们引入InternetExplorer服务和浏览器服务之前完全一样。我们有浏览器状态更改命令,但我们需要某种机制来触发它们。为此,我们将开发一个浏览器伪造组件,允许我们为应用程序的其余部分伪造浏览器环境。//browser-faker.component.tsimport{Component,OnDestroy,OnInit}from'@angular/core';import{FormControl}from'@angular/forms';从'rxjs'导入{Observable,Subject};从'rxjs/operators'导入{filter,takeUntil};从'./browser.service'导入{BrowserService};从'./fake-user-导入{FakeUserAgent}agent';@Component({host:{style:'display:block;'},selector:'browser-faker',templateUrl:'./browser-faker.component.html',})导出类BrowserFakerComponent实现OnDestroy,OnInit{privatedefaultOptionValue='';私人销毁=新主题();privatefakeBrowserSelection$:Observable;私有realBrowserSelection$:Observable;浏览器=Object.keys(FakeUserAgent);selectedBrowser=newFormControl(this.defaultOptionValue);wordStartPattern=/[A-Z]|\d+/g;constructor(privatebrowser:BrowserService,){this.realBrowserSelection$=this.selectedBrowser.valueChanges.pipe(filter(value=>value===this.defaultOptionValue),takeUntil(this.destroy),);}this.fakeBrowserSelection$=this.selectedBrowser.valueChanges.pipe(filter(value=>value!==this.defaultOptionValue),takeUntil(this.destroy),);}ngOnInit():void{this.bindEvents();}ngOnDestroy(){this.unbindEvents();}privatebindEvents():void{//一旦这个Observable有事发生,说明用户选择了假浏览器this.fakeBrowserSelection$.subscribe(userAgent=>this.browser.fakeUserAgent(userAgent));这个.realBrowserSelection$.subscribe(()=>this.browser.stopFakingUserAgent());}privateunbindEvents():void{this.destroy.next();this.destroy.complete();}}browserfaker组件注入浏览器服务,该服务具有绑定到本机选择控件的表单控件。选择浏览器后,我们开始通过浏览器服务伪造其用户代理。选择默认浏览器选项时,我们会停止伪造的用户代理。现在我们有一个浏览器假组件,但我们只希望在开发过程中启用它。让我们创建一个仅在开发模式下有条件地呈现的结构指令。创建一个注入令牌://is-development-mode.token.tsimport{InjectionToken,isDevMode}from'@angular/core';exportconstisDevelopmentModeToken:InjectionToken=newInjectionToken('Developmentmodeflag',{factory:():boolean=>isDevMode(),providedIn:'root',});//development-only.directive.tsimport{Directive,Inject,OnDestroy,OnInit,TemplateRef,ViewContainerRef,}from'@angular/core';import{isDevelopmentModeToken}from'./is-development-mode.token';@Directive({exportAs:'developmentOnly',selector:'[developmentOnly]',})exportclassDevelopmentOnlyDirective实现OnDestroy,OnInit{privategetisEnabled():boolean{返回this.isDevelopmentMode;}构造函数(私有容器:ViewContainerRef,私有模板:TemplateRef,@Inject(isDevelopmentModeToken)私有isDevelopmentMode:布尔值,){}ngOnInit():void{if(this.isEnabled){this.createAndAttachView();}}ngOnDestroy():void{this.destroyView();}privatecreateAndAttachView():void{this.container.createEmbeddedView(this.template);}privatedestroyView():void{this.container.clear();如果应用程序在开发模式下运行,此结构指令仅呈现它所附加的组件或元素,正如其测试套件所验证的那样现在,剩下的就是弃用横幅和浏览器伪装以添加到我们的应用程序中。URL:>browser-url>最终效果:选择IE11时,出现deprecation提示:选择其他浏览器时,提示消失:总结为了模拟用户环境,我们创建了adevelopment在模式中有条件地呈现的浏览器假组件。我们将浏览器状态封装在基于类的服务中,让应用程序依赖它。这与浏览器造假者使用的服务相同。浏览器伪造者是Angular应用程序中伪造依赖项的一个简单示例。我们讨论了动态配置Angular依赖注入机制的其他技术。本文提到的测试程序地址:https://stackblitz.com/edit/t...更多Jerry原创文章在这里:《王子熙》:

最新推荐
猜你喜欢