我正在试图弄清楚如何模拟ElementRef注入组件的东西.我的组件如下:
app.component.ts:
import { Component, ElementRef } from '@angular/core';
import { AppService } from './app.service';
@Component({
selector: 'app-root',
templateUrl: './app/app.component.html',
styleUrls: ['./app/app.component.css']
})
export class AppComponent {
title = 'app works!';
constructor(private _elementRef: ElementRef, private _appService: AppService) {
console.log(this._elementRef);
console.log(this._appService);
}
}
Run Code Online (Sandbox Code Playgroud)
我的测试规范如下:
app.component.spec.ts:
import { TestBed, async } from '@angular/core/testing';
import { ElementRef, Injectable } from '@angular/core';
import { AppComponent } from './app.component';
import { AppService } from './app.service';
@Injectable()
export class MockElementRef {
nativeElement: {}
}
@Injectable()
export class MockAppService {
}
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
providers: [
{provide: ElementRef, useClass: MockElementRef},
{provide: AppService, useClass: MockAppService}
]
}).compileComponents();
}));
...
});
Run Code Online (Sandbox Code Playgroud)
运行测试时console.log,构造函数中的输出app.component.ts是:
正如你所看到的,它注入了MockAppService但不是注入MockElementRef(尽管它们都以相同的方式被嘲笑).
这个SO帖子暗示你可以像任何其他模拟那样设置它,但是我注意到这是针对Angular 2的 - 所以我想知道Angular 4中是否有变化?
可以在此处找到具有上述代码和Jasmine测试的Plunker .运行Plunker然后单击"Run Unit Tests"链接以启动单元测试.可以在开发人员工具/ Firebug中观察控制台输出.
sho*_*ukh 19
简短的回答 -这是设计使然:)
让我们逐步深入研究更长的答案并尝试弄清楚 - 当我们通过TestBed.
第1步
根据test_bed.ts的源代码:
configureTestingModule(moduleDef: TestModuleMetadata): void {
if (moduleDef.providers) {
this._providers.push(...moduleDef.providers);
}
if (moduleDef.declarations) {
this._declarations.push(...moduleDef.declarations);
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
正如我们所看到的 -configureTestingModule方法只是将提供的实例推送到this._providers数组中。然后我们可以说:嘿TestBed,给我这个提供者ElementRef:
// ...
let elRef: ElementRef;
beforeEach(() => {
TestBed.configureTestingModule({
// ...
providers: [{provide: ElementRef, useValue: new MockElementRef()}]
});
// ...
elRef = TestBed.get(ElementRef);
});
it('test', () => {
console.log(elRef);
});
Run Code Online (Sandbox Code Playgroud)
在控制台中,我们将看到:
第一个控制台是从组件构造函数中记录的,第二个控制台是从测试中记录的。
所以,看起来我们正在处理两个不同的ElementRef. 让我们继续。
第2步
让我们看另一个例子,假设我们有一个注入的组件ElementRef和AppService我们之前创建的一些其他自定义服务:
export class HelloComponent {
constructor(private _elementRef: ElementRef, private _appService: AppService) {
console.log(this._elementRef);
console.log(this._appService);
}
}
Run Code Online (Sandbox Code Playgroud)
当我们测试这个组件-我们必须提供AppService(服务本身或其模拟),但,如果我们不提供ElementRef给TestBed-测试绝不会抱怨这样的:NullInjectorError: No provider for ElementRef!。
因此,我们可以建议,这ElementRef看起来不像依赖项,并且始终与组件本身相关联。我们离答案越来越近了。:)
第 3 步
让我们仔细看看如何TestBed创建组件:TestBed.createComponent(AppComponent). 这是源代码中非常简化的版本:
createComponent<T>(component: Type<T>): ComponentFixture<T> {
this._initIfNeeded();
const componentFactory = this._compiler.getComponentFactory(component);
// ...
const componentRef =
componentFactory.create(Injector.NULL, [], `#${rootElId}`, this._moduleRef);
return new ComponentFixture<T>(componentRef, ngZone, autoDetect);
// ...
}
Run Code Online (Sandbox Code Playgroud)
因此,我们必须继续检查源代码中ComponentFixture类的实现:
export class ComponentFixture<T> {
// The DebugElement associated with the root element of this component.
debugElement: DebugElement;
// The instance of the root component class.
componentInstance: T;
// The native element at the root of the component.
nativeElement: any;
// The ElementRef for the element at the root of the component.
elementRef: ElementRef;
// ...
constructor(
public componentRef: ComponentRef<T>, public ngZone: NgZone|null,
private _autoDetect: boolean) {
this.changeDetectorRef = componentRef.changeDetectorRef;
this.elementRef = componentRef.location;
// ...
Run Code Online (Sandbox Code Playgroud)
我们可以看到,这是初始化构造函数elementRef的ComponentFixture类的一个属性。
最后,总结以上——我们得到了答案:ElementRef在构造函数中注入到组件的实际上是围绕 DOM 元素的包装器。注入的实例ElementRef是对当前组件的宿主元素的引用。按照此StackOverflow 帖子获取有关它的更多信息。
这就是为什么在组件构造函数 console.log 中我们看到的是 的实例ElementRef而不是 的实例MockElementRef。所以,我们在 TestBed 提供者数组中实际提供的只是ElementRef基于MockElementRef.
| 归档时间: |
|
| 查看次数: |
6738 次 |
| 最近记录: |