Angular 2:如何在单元测试时模拟ChangeDetectorRef

Ank*_*ngh 13 unit-testing jasmine testbed typescript angular

我刚刚开始使用Unit-Testing,我已经能够模拟我自己的服务以及一些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 ??
    })
  ));
Run Code Online (Sandbox Code Playgroud)
 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 ??
  }));
Run Code Online (Sandbox Code Playgroud)
@Component({
  ...
})
export class MyComponent {
 constructor(private cdRef: ChangeDetectorRef){}

 ngOnInit() {
   // do something
   this.cdRef.markForCheck();
 }
}
Run Code Online (Sandbox Code Playgroud)

我已经尝试了一切,async,fakeAsync,injector([ChangeDetectorRef], () => {}).

什么都行不通.

Jua*_*uan 14

万一有人碰到这个,这是一种对我有用的方法:

当您在构造函数中注入ChangeDetectorRef实例时:

 constructor(private cdRef: ChangeDetectorRef) { }
Run Code Online (Sandbox Code Playgroud)

您将其cdRef作为组件上的私有属性之一,这意味着您可以监视组件,存根该属性并让它返回您想要的任何内容.此外,您可以根据需要断言其调用和参数.

在您的spec文件中,调用您的TestBed而不提供ChangeDetectorRef,因为它不会提供您提供的内容.设置相同beforeEach块的组件,因此它在规范之间重置,因为它在此处的文档中完成:

component = fixture.componentInstance;
Run Code Online (Sandbox Code Playgroud)

然后在测试中,直接监视属性

describe('someMethod()', () => {
  it('calls detect changes', () => {
    const spy = spyOn((component as any).cdRef, 'detectChanges');
    component.someMethod();

    expect(spy).toHaveBeenCalled();
  });
});
Run Code Online (Sandbox Code Playgroud)

有了间谍,你可以使用.and.returnValue()并让它返回你需要的任何东西.

请注意, (component as any)它用作cdRef私有属性.但私有在实际编译的JavaScript中不存在,因此可以访问.

如果您希望在运行时以这种方式访问​​测试的私有属性,则由您决定.我个人对它没有任何问题,我按照我的规格来做更多的报道.

  • 原始问题被宣布为私人问题。我刚刚回答了;)关于“我应该测试私有方法”的古老讨论有两个方面,是和否。两者都有正当的理由。我的建议是选择一个让您感到快乐的东西。 (2认同)

FDI*_*DIM 7

不确定这是否是新事物,但可以通过夹具访问 changeDetectorRef。

请参阅文档:https : //angular.io/guide/testing#componentfixture-properties

我们在更改检测器模拟方面遇到了同样的问题,这最终成为了解决方案

  • `fixture.changeDetectorRef` 与提供的组件不一样,所以你不能使用它。 (3认同)