Angular 7 Component Test使用的是原始服务而不是模拟 [英] Angular 7 Component Test is using original service instead of mock
问题描述
我正在尝试测试具有注入服务的组件.我想在测试中提供模拟服务.但是,测试使用的是原始服务而不是模拟服务(我知道这一点,因为我收到"No Client for HttpClient!"错误,并且在测试中输出的原始服务中也有console.log).
I am trying to test a component that has an injected service. I want to provide a mock service in my test. However the test is using the original service instead of the mock one (I know this because I am getting a "No provider for HttpClient!" error and also I have a console.log in the original service that is outputting in the test).
我可以通过导入HttpClientTestingModule来修复错误,但这不能解决使用原始服务而不是模拟服务这一事实.
I can fix the error by importing the HttpClientTestingModule but this doesn't fix the fact that the original service is being used instead of the mock one.
有任何想法我在做什么错吗?
Any ideas what I am doing wrong?
这是我的测试代码. Angular版本7
Here is my test code. Angular version 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'(未定义)"错误,感觉像是进度...
I have tried overrideProvider and now I am now getting a 'Cannot read property 'subscribe' of undefined' error, which sort of feels like progress...
这是我的测试代码
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);
}
}
推荐答案
我在上面的代码中看到了两个问题:
I see two issues in the code above:
- 您的TestBed的provider数组中有一组额外的方括号.我认为这不是主要问题,从语义上讲是不正确的.
- 在providers数组中提供
HelloWorldService
时,已指定了useClass
,但提供了一个对象(jasmine.createSpyObj()
产生的对象),因此应改为指定useValue
.
- You have an extra set of square brackets in the providers array of your TestBed. I don't think this is a major issue, it is just semantically incorrect.
- When you provide
HelloWorldService
in the providers array, you have specifieduseClass
, but have provided an object (which is whatjasmine.createSpyObj()
produces), so you should instead specifyuseValue
.
我希望这会有所帮助.
好的,您已经走了很长一段路!您已纠正了我上面概述的两个问题,正如我在对另一个答案的评论中所建议的那样,已经在compileComponents()
之前完成了overrideProvider()
,并将beforeEach()
包裹在了async()
内.
Ok, you have come quite a long ways! You corrected the two problems I outlined above, have done the overrideProvider()
before the compileComponents()
as I suggested in a comment to another answer as well as wrapped the beforeEach()
inside an async()
.
我要求查看所有其他代码的原因是,我可以将其快速放入以下 StackBlitz 进行测试.如您在StackBlitz中看到的那样,测试现在通过了.
The reason I asked to see all the other code was so I could quickly put it up in the following StackBlitz for testing. As you can see in that StackBlitz, the test is now passing.
我只在beforeEach()
中添加了一行以从您的间谍中声明returnValue,以便您组件中的订阅具有一个Observable来订阅:
I only added one line in the beforeEach()
to declare a returnValue from your spy, so that the subscribe in your component has an Observable to subscribe to:
mockHelloWorldService.getHelloWorld.and.returnValue(of('Test Message'));
我在调用fixture.detectChanges()
之前添加了此选项,因为它将调用ngOnInit()
,并且间谍在执行ngOnInit()
之前需要设置返回值,以便它可以正确执行,并且不会给您看到的错误.
I added this before the call to fixture.detectChanges()
since this will invoke ngOnInit()
, and the spy needs a return value set BEFORE executing ngOnInit()
so that it will execute correctly and not give you the error you were seeing.
我还在规范中添加了一行,以说明如何测试Observable的结果是否正确设置为组件变量:
I also added a line in the spec to show how you can test that the result of the Observable is correctly set to your component variable:
expect(component.helloWorldMessage).toEqual('Test Message');
请注意,通过在组件声明的providers数组中指定HelloWorldService,将使测试复杂化.相反,如果您以root身份作为单例提供此服务,则可以简化很多事情,包括如何进行测试.在官方文档中查看详细信息.
Note that you are significantly complicating your testing by specifying the HelloWorldService in the providers array of your component declaration. If you instead provide this service as a singleton in root that will simplify things a lot, including how you test. See details in the Official Docs.
这篇关于Angular 7 Component Test使用的是原始服务而不是模拟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!