Angular 7 Component Test使用的是原始服务而不是模拟

时间:2019-01-04 09:23:38

标签: angular unit-testing mocking

我正在尝试测试具有注入服务的组件。我想在测试中提供模拟服务。但是,该测试使用的是原始服务而不是模拟服务(我知道这一点是因为我收到“ HttpClient没有提供者!”错误,并且在测试中输出的原始服务中也有console.log)。

我可以通过导入HttpClientTestingModule来修复错误,但这不能解决使用原始服务而非模拟服务这一事实。

有什么想法我做错了吗?

这是我的测试代码。 Angular版本7

import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { HelloWorldComponent } from '../../app/components/hello-world/hello-world.component';
import { HelloWorldService } from '../../app/services/hello-world.service';

describe('HelloWorldComponent', () => {

  let component: HelloWorldComponent;
  let fixture: ComponentFixture<HelloWorldComponent>;
  let mockHelloWorldService;
  
  beforeEach(() => {

    mockHelloWorldService = jasmine.createSpyObj(['getHelloWorld']);
    
    TestBed.configureTestingModule({
      imports: [],
      declarations: [HelloWorldComponent],
      providers: [
        [{ provide: HelloWorldService, useClass: mockHelloWorldService }]
      ]
    }).compileComponents();

    fixture = TestBed.createComponent(HelloWorldComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
	
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
  
});

更新

我尝试了overrideProvider,现在遇到了“无法读取未定义的属性'subscribe'(未定义)”错误,感觉像是进度...

这是我的测试代码

import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { HelloWorldComponent } from '../../app/components/hello-world/hello-world.component';
import { HelloWorldService } from '../../app/services/hello-world.service';
import { of } from 'rxjs';

describe('HelloWorldComponent', () => {

  let component: HelloWorldComponent;
  let fixture: ComponentFixture<HelloWorldComponent>;
  let mockHelloWorldService;

  beforeEach(async(() => {
    mockHelloWorldService = jasmine.createSpyObj(['getHelloWorld']);
    TestBed.configureTestingModule({
      imports: [],
      declarations: [HelloWorldComponent]
    });
    TestBed.overrideProvider(HelloWorldService, { useValue: mockHelloWorldService });
    TestBed.compileComponents();

  }));

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

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

这是我的组成部分

import { Component, OnInit } from '@angular/core';
import { HelloWorldService } from '../../services/hello-world.service';

@Component({
  selector: 'app-hello-world',
  templateUrl: './hello-world.component.html',
  providers: [HelloWorldService]
})
export class HelloWorldComponent implements OnInit {

  helloWorldMessage: any;
  constructor(private helloWorldService: HelloWorldService) { }

  ngOnInit() {
    this.getHelloWorldMsg();
  }

  getHelloWorldMsg() {
    this.helloWorldService
      .getHelloWorld()
      .subscribe((data) => {
        this.helloWorldMessage = data;
        }, err => this.handleErrorResponse('There was a problem loading the hello world message', err));
  }

  handleErrorResponse(errorMsg: string, error?: any) {
    console.log("There was a problem getting the message");
  }
}

这是我的服务

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

import { environment } from '../../environments/environment';

@Injectable()
export class HelloWorldService {
  constructor(private http: HttpClient) { }

  getHelloWorld(): Observable<any> {
    console.log("Why is the test coming here when I provide a mock?");
    var getHelloWorldApiUrl = environment.apiUrl + "/api/v1.0/helloworld/GetHelloWorldMessageAuth";
    return this.http
    .get(getHelloWorldApiUrl);
  }
}

2 个答案:

答案 0 :(得分:1)

也许您的HelloWorldService是在组件提供程序中声明的。因此,您需要使用https://angular.io/api/core/testing/TestBed#overrideComponent来替换提供程序。

答案 1 :(得分:1)

我在上面的代码中看到两个问题:

  • TestBed的providers数组中有一组额外的方括号。我认为这不是主要问题,只是语义上不正确。
  • 在providers数组中提供HelloWorldService时,您已指定useClass,但提供了一个对象(jasmine.createSpyObj()产生的对象),因此应改为指定{{1 }}。

我希望这会有所帮助。

更新:

好的,您已经走了很长一段路!您纠正了我上面概述的两个问题,按照我在对另一个答案的评论中的建议,在useValue之前完成了overrideProvider()并将compileComponents()包裹在beforeEach()

我要求查看所有其他代码的原因是,我可以将其快速放入以下StackBlitz中进行测试。正如您在该StackBlitz中看到的那样,该测试现在通过了。

我只在async()中添加了一行以从您的间谍中声明returnValue,以便您组件中的订阅具有一个Observable来订阅:

beforeEach()

我在调用mockHelloWorldService.getHelloWorld.and.returnValue(of('Test Message')); 之前添加了此内容,因为它将调用fixture.detectChanges(),并且间谍需要在执行ngOnInit()之前设置返回值,这样它才能正确执行而不会给您您看到的错误。

我还在规范中添加了一行,以展示如何测试Observable的结果是否正确设置为组件变量:

ngOnInit()

请注意,通过在组件声明的providers数组中指定HelloWorldService,将使测试变得非常复杂。相反,如果您以root身份作为单例提供此服务,则可以简化很多事情,包括如何进行测试。在Official Docs中查看详细信息。