错误:期望调用spy create但未被调用

3

我正在为一个带有异步服务的组件编写Angular 7单元测试用例,但是遇到了以下错误:

错误:预期spy create已被调用一次。它被调用了0次。

这是我的组件:

export class RegistrationComponent implements OnInit {
    
   submitRegistrationForm() {
        if (this.profileForm.invalid) {
          this.validateAllFields(this.profileForm);
        } else {
          // send a http request to save this data
          this.guestUserService.create(this.profileForm.value).subscribe(
            result => {
              if (result) {
                console.log('result', result);
                this.router.navigate(['/login']);
              }
            },
            error => {
              console.log('error', error);
            });
        }
  }

单元测试用例:

  describe('RegistrationComponent', () => {
      let component: RegistrationComponent;
      let fixture: ComponentFixture<RegistrationComponent>;
      let myService;
      let mySpy;
    
      beforeEach(async(() => {
    
        TestBed.configureTestingModule({
          declarations: [RegistrationComponent],
          imports: [ ],
          providers: [
            { provide: GuestUserService, useValue: new MyServiceStub() }]
        })
          .compileComponents();
      }));
    
      beforeEach(() => {
        fixture = TestBed.createComponent(RegistrationComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
      });

 it('should submit Registration Form', async(inject([Router], (router) => {
    myService = TestBed.get(GuestUserService);
    mySpy = spyOn(myService, 'create');
    spyOn(router, 'navigate');
    spyOn(component, 'submitRegistrationForm');


component.profileForm.controls['firstName'].setValue('Arjun');
    component.profileForm.controls['lastName'].setValue('Singh');
    component.profileForm.controls['password'].setValue('12345678');
    component.profileForm.controls['confirmPassword'].setValue('12345678');
    component.submitRegistrationForm();

    expect(component.profileForm.invalid).toBe(false);

    expect(component.submitRegistrationForm).toHaveBeenCalled();

    expect(myService).toBeDefined();
    expect(mySpy).toBeDefined();
    expect(mySpy).toHaveBeenCalledTimes(1); // Getting error is this
    expect(router.navigate).toHaveBeenCalled();
  })
  ));

我尝试在beforeEach中移动spy的减速,但仍然出现相同的错误。
如何修复此错误?
谢谢!

你能否将显示错误的代码行更改为以下内容并尝试 - expect(myService.create).toHaveBeenCalledTimes(1); - user2216584
在调用测试方法之后,在编写 expects 之前,您需要执行 detectChanges 或者注入 done 并调用它。 - The Head Rush
1
你好 @user2216584,我已经尝试了这个 expect(myService .create).toHaveBeenCalledTimes(1); 但还是得到了同样的错误 :( - Arjun Singh
嗨@TheHeadRush,fixture.detectChanges();也没有起作用。 - Arjun Singh
1
@ArjunSingh 看起来你的组件的 else 条件没有被执行。在 if 和 else 条件中放置 console.log 并查看记录了什么。从你的测试用例来看,似乎你的组件的 this.profileForm 是无效的,因此你的 submitRegistrationForm 方法的 else 条件没有被执行。你确定 submitRegistrationForm 的 else 条件被调用了吗?放置日志并检查。 - user2216584
@user2216584,没有设置profileForm的值,因此获取this.profileForm.invalid为false,即需要执行else条件。已更新测试用例。 - Arjun Singh
2个回答

22

预期的间谍创建被调用不是错误,而是测试失败。

这是因为您在 spyOn 上没有使用 callThrough();。

 it('should submit Registration Form', async(inject([Router], (router) => {

    myService = TestBed.get(GuestUserService);
    mySpy = spyOn(myService, 'create').and.callThrough(); //callThrough()

    spyOn(router, 'navigate');

    spyOn(component, 'submitRegistrationForm').and.callThrough(); //callThrough()


    component.submitRegistrationForm();

    expect(component.profileForm.invalid).toBe(false);

    expect(component.submitRegistrationForm).toHaveBeenCalled();

    expect(myService).toBeDefined();
    expect(mySpy).toBeDefined();
    expect(mySpy).toHaveBeenCalledTimes(1); 
    expect(router.navigate).toHaveBeenCalled();
  })
  ));

谢谢您。它在表单控件方面非常有效。 - Bidisha Das

8
spyOn会帮助您在测试中设置函数被调用时应如何反应。本质上,这是Jasmine创建模拟的方式。
在您的情况下,您已经定义了当服务函数被调用时测试应该执行的操作,即callThrough。问题在于,您还需要对服务函数(或调用您的服务方法的作用域函数)进行操作,以触发spyOn并进行callThrough操作。
it('load snapshot',function(){

  //setup
  spyOn(MyService, 'loadSomething').and.callThrough(); //statement 2

  //act

  //either call the scope function which uses the service 
  //$scope.yourServiceCallFunction();

  //or call the service function directly
  MyService.loadSomething(1); //this will callThrough

});

这是一个简单的测试,我们将模拟 spyOn 的响应为字符串。
it('test loadSomething',function(){

  //setup
  spyOn(MyService, 'loadSomething').and.returnValue('Mocked');

  //act
  var val = MyService.loadSomething(1);

  //check
  expect(val).toEqual('Mocked');
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接