我刚刚开始使用单元测试,我已经能够模拟我自己的服务,以及一些Angular和Ionic,但无论我做什么,ChangeDetectorRef
都保持不变。
我是说这是哪种巫术?
beforeEach(async(() =>
TestBed.configureTestingModule({
declarations: [MyComponent],
providers: [
Form, DomController, ToastController, AlertController,
PopoverController,
{provide: Platform, useClass: PlatformMock},
{
provide: NavParams,
useValue: new NavParams({data: new PageData().Data})
},
{provide: ChangeDetectorRef, useClass: ChangeDetectorRefMock}
],
imports: [
FormsModule,
ReactiveFormsModule,
IonicModule
],
})
.overrideComponent(MyComponent, {
set: {
providers: [
{provide: ChangeDetectorRef, useClass: ChangeDetectorRefMock},
],
viewProviders: [
{provide: ChangeDetectorRef, useClass: ChangeDetectorRefMock},
]
}
})
.compileComponents()
.then(() => {
let fixture = TestBed.createComponent(MyComponent);
let cmp = fixture.debugElement.componentInstance;
let cdRef = fixture.debugElement.injector.get(ChangeDetectorRef);
console.log(cdRef); // logs ChangeDetectorRefMock
console.log(cmp.cdRef); // logs ChangeDetectorRef , why ??
})
));
it('fails no matter what', async(() => {
spyOn(cdRef, 'markForCheck');
spyOn(cmp.cdRef, 'markForCheck');
cmp.ngOnInit();
expect(cdRef.markForCheck).toHaveBeenCalled(); // fail, why ??
expect(cmp.cdRef.markForCheck).toHaveBeenCalled(); // success
console.log(cdRef); // logs ChangeDetectorRefMock
console.log(cmp.cdRef); // logs ChangeDetectorRef , why ??
}));
@Component({
...
})
export class MyComponent {
constructor(private cdRef: ChangeDetectorRef){}
ngOnInit() {
// do something
this.cdRef.markForCheck();
}
}
我已经尝试了所有的东西,async
,fakeAsync
,injector([ChangeDetectorRef], () => {})
。
什么都不管用。
6条答案
按热度按时间iyfjxgzm1#
更新2020:
我最初在2017年5月写了这篇文章,这是一个当时效果很好的解决方案,现在仍然有效。
我们不能通过测试床配置changeDetectorRef mock的注入,所以这是我这些天正在做的事情:
那么你就不需要关心私有属性或任何东西。
如果有人遇到这种情况,这是一种对我很有效的方法:
当您在构造函数中注入ChangeDetectorRef示例时:
您将
cdRef
作为组件上的私有属性之一,这意味着您可以监视组件,存根该属性并让它返回任何您想要的内容。此外,您还可以根据需要Assert其调用和参数。在你的spec文件中,调用你的TestBed而不提供ChangeDetectorRef,因为它不会提供你给予它的东西。设置相同的组件beforeEach块,因此它在规格之间重置,如此处的文档所示:
然后在测试中,直接监视属性
有了间谍,你可以使用
.and.returnValue()
,并让它返回你需要的任何东西。请注意,使用
(component as any)
是因为cdRef
是私有属性。但是private并不存在于实际编译的javascript中,所以它是可访问的。如果您希望在运行时以这种方式访问私有属性,这取决于您。
1yjd4xko2#
不确定这是否是一个新的东西,但changeDetectorRef可以通过fixture访问。
参见文档: www.example.com
我们遇到了相同的问题与变化检测器模拟,这是结束了解决方案
v9tzhpje3#
可能需要指出的一点是,本质上你想测试你自己的代码,而不是单元测试变更检测器本身(这是由Angular团队测试的)。在我看来,这是一个很好的指标,你应该提取调用变化检测器到一个本地私有方法(私有的,因为它是你不想单元测试的东西),e。g的。
然后,在单元测试中,您需要验证代码是否实际调用了该函数,从而从ChangeDetectorRef调用了该方法。例如:
我也遇到过同样的情况,这是一位高级开发人员作为单元测试的一般最佳实践向我建议的,他告诉我,单元测试实际上是通过这种模式迫使你更好地构建代码。通过建议的重组,您可以确保代码可以灵活更改。例如,如果Angular改变了他们为我们提供变化检测的方式,那么你只需要调整detectChanges方法。
vc9ivgsu4#
对于单元测试,如果你模拟
ChangeDetectorRef
只是为了满足要创建的组件的依赖注入,你可以传入任何值。对于我的情况,我是这样做的:
它将成功创建
myComponent
。只需确保测试执行路径不需要ChangeDetectorRef
即可。如果是这样,那么用一个适当的mock对象替换useValue: {}
。在我的例子中,我只需要使用
FormBuilder
测试一些表单创建的东西。arknldoa5#
iswrvxsc6#
我看到了很多好的答案。
2023年,我开玩笑地说: