如何调用模拟方法而不被间谍检测到?

How can a mocked method be called and not be detected by spy?

这是我的组件:

@Component({
    selector: 'app-signup',
    templateUrl: './signup.component.html',
    styleUrls: ['./signup.component.scss']
})
export class SignUpComponent implements OnInit {
    specialLink: string;

    constructor(
        private activatedRoute: ActivatedRoute,
    ) {
        this.specialLink = this.activatedRoute.snapshot.params.id;
        console.log('TEST1', this.specialLink);

        if (this.specialLink !== undefined) {
            this.setSpecialSignup();
        }
    }

    setSpecialSignup() {
        console.log("CALLED;");
    }

这是我的测试:

describe('SignUpComponent', () => {
  let component: SignUpComponent;
  let fixture: ComponentFixture<SignUpComponent>;
  let ActivatedRouteMock: any;
  
  beforeEach(async(() => {
    ActivatedRouteMock = {
      snapshot: {
        params: { id: 123 }
      },
    };

    TestBed.configureTestingModule({
      declarations: [ SignUpComponent ],
      imports: [ RouterTestingModule ],
      providers: [
        {provide: ActivatedRoute, useValue: ActivatedRouteMock}
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(SignUpComponent);
    component = fixture.componentInstance;
  });


  describe('Patient Side', () => {
    it('should call setSpecialSignup() when user is coming from specialLink', () => {
      spyOn(component, 'setSpecialSignup');
      fixture.detectChanges();
      expect(component.setSpecialSignup).toHaveBeenCalled();
    });

我正在测试是否调用了 setSpecialSignup。它是! 2'console.log'证明了。那么,为什么会出现此错误:Expected spy setSpecialSignup to have been called.? 我错过了什么?

看来我需要能够更改 ActivatedRouteMock.snapshot.params.id 的值。有时它必须是未定义的,有时它必须是 'something'。我怎样才能做到这一点 ?我试过 ActivatedRouteMock.snapshot.params.id = 'something' 但它根本没有改变值,即使使用 fixture.detectChanges() 也是如此。我该怎么做?

你能把你放在构造函数中的代码移动到 ngOnInit()

@Component({
    selector: 'app-signup',
    templateUrl: './signup.component.html',
    styleUrls: ['./signup.component.scss']
})
export class SignUpComponent implements OnInit {
    specialLink: string;

    constructor(
        private activatedRoute: ActivatedRoute,
    ) {
       
    }
ngOnInit(){
 this.specialLink = this.activatedRoute.snapshot.params.id;
        console.log('TEST1', this.specialLink);

        if (this.specialLink !== undefined) {
            this.setSpecialSignup();
        }
}

    setSpecialSignup() {
        console.log("CALLED;");
    }

你能试试下面的代码吗?

describe('SignUpComponent', () => {
  let component: SignUpComponent;
  let fixture: ComponentFixture<SignUpComponent>;
  let ActivatedRouteMock: any;
  
  beforeEach(async(() => {
    ActivatedRouteMock = {
      snapshot: {
        params: { id: 123 }
      },
    };

    TestBed.configureTestingModule({
      declarations: [ SignUpComponent ],
      imports: [ RouterTestingModule ],
      providers: [
        {provide: ActivatedRoute, useValue: ActivatedRouteMock}
      ]
    })
  .compileComponents().then(() => {
          fixture = TestBed.createComponent(PriceModelListComponent);
          component = fixture.componentInstance;         
        });
  }));

 
  describe('Patient Side', () => {
    it('should call setSpecialSignup() when user is coming from specialLink', () => {
      spyOn(component, 'setSpecialSignup');
      fixture.detectChanges();
      expect(component.setSpecialSignup).toHaveBeenCalled();
    });

模拟参数

规范中的提供者内部

providers: [ { provide: ActivatedRoute, useValue: { // Mock queryParams: of( { id_params: 'id_params_test' } ), params: of( { id_query_params: 'id_query_params_test' } ) } } ],

正如我们所见,setSpecialSignupconstructor 内部被调用。 constructor 在此行 fixture = TestBed.createComponent(SignUpComponent); 上被调用。而你创造一个间谍为时已晚。如果您希望此功能更容易测试,请将组件的逻辑移动到 ngOnInit 生命周期挂钩。它将在第一个 fixture.detectChanges() 上被调用,你的测试应该没问题

constructor(
        private activatedRoute: ActivatedRoute,
    ) { }
   ngOnInit() {
        this.specialLink = this.activatedRoute.snapshot.params.id;
        console.log('TEST1', this.specialLink);

        if (this.specialLink !== undefined) {
            this.setSpecialSignup();
        }
    }