Angular 单元测试 - 模拟 REST 服务调用

Angular Unit Testing - Mocking a REST service call

我正在为 Angular 应用程序编写单元测试以测试前端功能,并尝试生成一种方法来模拟以下场景的休息服务调用:

我有一个class定义如下:

import { Component, OnInit } from '@angular/core';
import {RestService} from "../../../../../services/rest.service";
import {ActivatedRoute, Router} from "@angular/router";

@Component({
  selector: 'app-example-class’,
  templateUrl: ‘./example-class.component.html',
  styleUrls: [‘./example-class.component.scss']
})
export class ExampleClass implements OnInit {

  myData: any = [];
  reloadInterval: any;
  constructor(private rest: RestService) {
    this.reloadInterval = setInterval(() => {
      this.getData();
    }, 10000);
  }

  ngOnInit() {
    this.getData();
  }

  ngOnDestroy(){
    clearInterval(this.reloadInterval);
  }

  getData() {
    this.rest.call(‘exampleClass’, this.rest.id).subscribe((data: {}) => {
      if (data['rows']) {
        this.myData = data['rows'].reduce((accumulator, currRow)=> accumulator + currRow.value, 0);
      }
    });
  }
}

我想使用 Karma/Jasmine 单元测试框架专门测试我的 "getData()" 方法。这是我创建的:

describe(‘ExampleClassComponent', () => {
  let component: ExampleClass;
  let fixture: ComponentFixture<ExampleClass>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        HttpClientTestingModule,
      ],
      declarations: [ ExampleClass ]
    })
    .compileComponents();
  }));

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

  it('should create',
    inject(
      [HttpTestingController],
      (httpMock: HttpTestingController) => {
    expect(component).toBeTruthy();
  }));
});

这行得通。组件被创建并且测试通过。但是,当我尝试执行以下操作时:

it('should test number of elements', ()=>{
    component.getData();
    expect(component.myData.length).toBe(1);
 });

这失败了。它失败了,因为它试图通过对不是 运行 的服务的剩余调用来调用 getData() 方法。我想以某种方式模拟在该函数中进行的其余调用。我试过在我的测试 class 中创建一个 MockRestService class 是这样的:

class MockRestService extends RestService {
  myData = [
    {myData: 1}
  ];

  call(endpoint: string, params?: Object, data?: any, queryString?: string, isCustomUri?: boolean): Observable<any> {
    return of(this.myData);
  }
}

然后修改我的测试:

  it('should test number of elements', ()=>{
    let mockRestService = new MockRestService(null);
    component = new ExampleClass(mockRestService);
    component.getData();
    expect(component.myData.length).toBe(1);
  });

但这不起作用。是否可以模拟 getData 中进行的其余调用以进行测试,如果可以,如何模拟?非常感谢您的帮助!

您不需要单独的 MockRestService class 但可以使用 Jasmine 的 spyOn 来模拟 RestService.call 方法。这可能如下所示。

it('should test number of elements', ()=> {

    // given
    const restService = TestBed.inject(RestService);
    const data = {} // define your rest call data
    spyOn(restService, 'call').and.returnValue(of(data));

    // when
    component.getData();

    // then
    expect(component.myData.length).toBe(1);
});