如何使用依赖项测试Angular服务?

时间:2020-01-12 22:58:08

标签: angular unit-testing karma-jasmine

我想对与另一个服务有依赖性的服务进行单元测试。

my.service.ts:

@Injectable({
  providedIn: 'root',
})
export class MyService {
  readonly initialObjects = [
    { title: 'Title1', url: '/title1' },
    { title: 'Title2', url: '/title2' },
    { title: 'Title3', url: '/title3' },
  ];

  objects$ = new BehaviorSubject(null);

  constructor(private anotherService: AnotherService) {
    this.updateObjects();
  }

  updateObjects() {
    this.anotherService.getAllObjects().subscribe(objects => {
      if (objects.length === 0) {
        this.objects$.next(this.initialObjects);
      } else {
        const newObjects = [];
        objects.forEach(object => {
          newObjects.push({ title: object.name, url: `some-fancy-url/${object.id}` });
        });
        this.objects$.next([...this.initialObjects, ...objects]);
      }
    });
  }
}

my.service.spec.ts

import { TestBed } from '@angular/core/testing';
import { of } from 'rxjs';
import { AnotherService } from '../another.service';
import { MyService } from './my.service';

describe('MyService', () => {
  let service: MyService;
  let mockAnotherService;

  const mockObjects = [
    { id: '70c3d78c-90d9-44f6-aadc-ba2b993ba741', title: 'title1' },
    { id: 'fa08a156-edf6-4a42-bdae-99d91b5c6f32', title: 'title2' },
    { id: '551849d8-9b36-45d6-b6de-154f700abbcc', title: 'title3' },
  ];

  beforeEach(() => {
    mockAnotherService = jasmine.createSpyObj(['getAllObjects']);

    TestBed.configureTestingModule({
      providers: [
        MyService,
        { provide: AnotherService, useValue: mockAnotherService }
      ],
    });

    service = TestBed.get(MyService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });

  describe('objects observable', () => {
    it('should contain only initial objects', () => {
      mockAnotherService.getAllObjects.and.returnValue(of([]));

      expect(service.objects$.value.length).toBe(3);
    });

    it('should contain all initial objects and all other available objects', () => {
      mockAnotherService.getAllObjects.and.returnValue(of(mockObjects));

      expect(service.objects$.value.length).toBe(6);

      for (let index = 3; index < service.objects$.value.length; index++) {
          expect(service.objects$.value[index].title).toEqual(mockObjects[index].title);
      }
    });
  });
});

another.service.ts(已缩短)

[...]

  private objects = [];

  getAllObjects() {
    return of(this.objects);
  }

[...]

我为所有测试得到的错误消息是:

...
TypeError:无法读取未定义的属性“ subscribe”
在茉莉花
在MyService.updateObjects(http://localhost:9877/_karma_webpack_/main.js:3667:55
...

我认为,我使用jasmine.createSpyObj创建了一个间谍,它将通过工厂提供。我在这里想念什么吗?

1 个答案:

答案 0 :(得分:0)

由于您是在构造函数中调用服务的,因此任何测试用例都无法模仿该服务。相反,您可以执行以下操作

  const mockObjects = [
    { id: '70c3d78c-90d9-44f6-aadc-ba2b993ba741', title: 'title1' },
    { id: 'fa08a156-edf6-4a42-bdae-99d91b5c6f32', title: 'title2' },
    { id: '551849d8-9b36-45d6-b6de-154f700abbcc', title: 'title3' },
  ];

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        MyService,
        { 
          provide: AnotherService, 
          useValue: { // you can create your fake service right here
            getAllObjects: () => of(mockObjects)
          }
        }
      ],
    });
    service = TestBed.get(MyService);
  });