如何在Angular组件中模拟服务功能以进行单元测试

时间:2019-10-10 21:26:23

标签: angular typescript unit-testing

我正在为angular应用编写单元测试,正在测试服务功能是否返回值。

component.spec.ts

import {TopToolBarService} from '../../top-toolbar/top-toolbar.service';

beforeEach(async(() => {
   TestBed.configureTestingModule ({
   declarations: [ UsersListComponent],
   providers: [TopToolBarService],//tried mocking service here,still test failed
   schemas:[CUSTOM_ELEMENTS_SCHEMA]
 })
  .compileComponents();
}));



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



  it('should return data from service function', async(() => {
    let mockTopToolBarService: jasmine.SpyObj<TopToolBarService>;
    mockTopToolBarService = jasmine.createSpyObj('TopToolBarService', ['getCustomer']);
    mockTopToolBarService.getCustomer.and.returnValue("king");
    fixture.detectChanges();
    expect(component.bDefine).toBe(true); //fails
  }))

component.ts

bDefine = false;
ngOnInit() {
 let customer = this.topToolBarService.getCustomer();
 if (customer == null) {
   bDefine = false;
 } else {
    bDefine = true;
   }
}

我相信我在测试中嘲笑了服务函数,因此我希望它必须到达变量设置为“ true”的其他部分。

TopToolBarService.ts

import { EventEmitter, Injectable, Output } from "@angular/core";

@Injectable()
export class TopToolBarService {
customer = null;

  getCustomer() {
    return this.customer;
  }
}

5 个答案:

答案 0 :(得分:1)

尝试更新beforeEach(async(()=> ...)内的提供程序,并将您的mockedService变量移至其顶部:

(keyup)="onKey($event)"

希望有帮助!

答案 1 :(得分:1)

更改您的提供商价值

beforeEach(() => {
   TestBed.configureTestingModule({
      declarations: [ UsersListComponent],
      providers: [{
         provide: TopToolBarService,
         useValue: jasmine.createSpyObj('TopToolBarService', ['getCustomer'])
      }],
      schemas:[CUSTOM_ELEMENTS_SCHEMA]
     });
     mockTopToolBarService = TestBed.get(TopToolBarService);

     mockTopToolBarService.getCustomer.and.returnValue(of([])); // mock output of function
   })

答案 2 :(得分:0)

在运行代码之前,您必须配置测试模块。除非您将其作为导入对象传递给TestBed.configureTestingModule,否则它不会知道您的间谍对象。

https://angular.io/guide/testing#component-with-a-dependency

答案 3 :(得分:0)

您可以考虑使用 ng-mocks 来避免配置 TestBed 的所有样板。

beforeEach(() => MockBuilder(UsersListComponent)
  .mock(TopToolBarService, {
    // adding custom behavior to the service
    getCustomer: jasmine.createSpy().and.returnValue('king'),
  })
);

it('should return data from service function', () => {
  const fixture = MockRender(UsersListComponent);
  // now right after the render the property should be true
  expect(fixtur.point.componentInstance.bDefine).toBe(true);
}));

答案 4 :(得分:0)

@Pedro Bezanilla 的回答已经足够好了。这是另一种代码更少的方法,因为服务是单例,我认为这是大多数情况。

不同之处在于没有为 configureTestingModule 提供提供程序配置。间谍是由 spyOn 针对从 TestBed 获取的服务对象设置的。

调用 TestBed.inject 而不是 TestBed.get 是因为它自 v9.0.0 以来已被弃用。

对于单例服务,这里是a doc in Angular website,为了完成,请记住this GitHub issue

describe('Component TEST', () => {
  ...
  let mockToolBarService: TopToolBarService;
  ...
  beforeEach(waitForAsync(() => {
    TestBed.configureTestingModule({
      declarations: [ UsersListComponent ],
      schemas:[ CUSTOM_ELEMENTS_SCHEMA ]
    });
    mockTopToolBarService = TestBed.inject(TopToolBarService);
    spyOn(mockTopToolBarService, 'getCustomer').and.returnValue(of([]));
  }));
  ...