我在ng 4中对基本@Injectable
服务进行单元测试。教程使用不同的约定(例如使用TestBed
vs debugElement.injector
)。当这些测试通过时,我的设置感觉拼凑在一起,可能会使用不良的约定。
以下是我的担忧:
providers
的声明似乎很详细,但providers: [MockProgressServer]
导致了业力错误。expect(component).ToBeTruthy
?这似乎是由其他模块中的ng cli自动生成的。fixture.debugElement.injector.get(ProgressService)
似乎与TestBed.get(ProgressService)
一致。哪个更适合?async()
?我们正在测试的课程ProgressService
progress.service.ts
。它很简单,包含一个currentState
字段getters
和setters
。
import { Injectable } from '@angular/core';
@Injectable()
export class ProgressService {
private currentState: string = '1';
constructor() {
}
setCurrentState(state: string) {
this.currentState = state;
}
getCurrentState(){
return this.currentState
}
}
因为这个类很简单,所以相应的Mock
不会覆盖任何内容。
import {ProgressService} from "../../../progress.service";
export class MockProgressService extends ProgressService {
}
我拼凑了以下progress.spec.ts
课程来对吸气剂和制定者进行单元测试。
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ProgressComponent } from './progress.component';
import {MockProgressService} from "../shared/services/progress/progress.mock1";
import {ProgressService} from "../progress.service";
describe('ProgressComponent', () => {
let component: ProgressComponent;
let fixture: ComponentFixture<ProgressComponent>;
let mockService: ProgressService;
beforeEach(async() => {
TestBed.configureTestingModule({
declarations: [ ProgressComponent ],
providers: [{provide: ProgressService, useValue: new MockProgressService()}]
}).compileComponents()
fixture = TestBed.createComponent(ProgressComponent);
component = fixture.componentInstance;
mockService = fixture.debugElement.injector.get(ProgressService)
fixture.detectChanges();
});
fit('The component should be created', () => {
expect(component).toBeTruthy();
});
fit('ProgressService default currentState is "1"', () =>{
expect(mockService.getCurrentState()).toEqual('1')
})
fit('ProgressService new currentState is "5"', () =>{
mockService.setCurrentState('5')
expect(mockService.getCurrentState()).toEqual('5')
})
});
npm test
表明这些传递
感谢。我希望在继续讨论非常重要的案件之前将其锁定。
PS,有没有办法改变Karma浏览器报告的样式? (EG使字体更大?)
拆分测试模块。 首先,测试服务:
import {async, ComponentFixture, getTestBed, TestBed} from '@angular/core/testing';
import { ProgressComponent } from './progress.component';
import {ProgressService} from "../progress.service";
describe('ProgressComponent', () => {
let injector: TestBed;
let service: ProgressService;
beforeEach(async() => {
TestBed.configureTestingModule({
providers: [ProgressService]
}).compileComponents()
injector = getTestBed()
service= injector.get(ProgressService)
});
fit('ProgressService default currentState is "1"', () =>{
expect(service.getCurrentState()).toEqual('1')
})
fit('ProgressService new currentState is "5"', () =>{
service.setCurrentState('5')
expect(service.getCurrentState()).toEqual('5')
})
});
两件事:
我对provider / TestBed.get()的使用是否正确?为什么我不能自己实例化ProgressService实例? TestBed是否确保创建单例?
不确定fakeAsync
的建议适合...
接下来,测试组件:
import {async, ComponentFixture, getTestBed, TestBed} from '@angular/core/testing'
import { ProgressComponent } from './progress.component'
import {MockProgressService} from "../shared/services/progress/progress.mock1"
import {ProgressService} from "../progress.service"
describe('ProgressComponent', () => {
let injector: TestBed
let mockService: ProgressService
let fixture: ComponentFixture<ProgressComponent>
let component: ProgressComponent
beforeEach(async() => {
TestBed.configureTestingModule({
declarations: [ ProgressComponent ],
providers: [{provide: ProgressService, useClass: MockProgressService}]
}).compileComponents()
injector = getTestBed()
fixture = TestBed.createComponent(ProgressComponent)
component = fixture.componentInstance
mockService = injector.get(ProgressService)
fixture.detectChanges();
});
fit('The component should be created', () => {
expect(component).toBeTruthy();
});
fit('The service should be an instance of MockService', () => {
expect(mockService instanceof MockProgressService).toBeTruthy()
})
});
答案 0 :(得分:2)
通常,服务测试不应包含declarations
和TestBed.createComponent
。组件会产生额外的移动部件,并可能影响测试结果。 ProgressService
当然不需要在自己的测试中嘲笑。实际上,ProgressService default currentState
等和The component should be created
属于两种不同的试验台设置。一个有providers: [ProgressService]
,另一个有declarations: [ ProgressComponent ]
和MockProgressService
。
此处使用providers: [MockProgressService]
不正确,因为正在使用的DI令牌为ProgressService
,并且必须嘲笑此提供程序。 providers
应该是:
providers: [{provide: ProgressService, useClass: MockProgressService}]
expect(component).ToBeTruthy
断言不是必需的,但可能有用,因为测试环境中有一些条件会导致beforeEach
阻止静默失败,而The component should be created
测试是可以确定这个的问题毫不含糊。
fixture.debugElement.injector.get(ProgressService)
可以安全地替换为TestBed.get(ProgressService)
此处,这就是TestBed.get
和inject
助手的用途。但是这两个不可互换因为TestBed.get
从根注入器检索服务实例,而fixture.debugElement.injector
是组件注入器并且可以访问特定于组件的实例。此外,如果这是没有组件的试验台,则不会有fixture
。
根据经验,测试应该使用fakeAsync
助手 - 只是因为它会导致零延迟并完成工作。它应该开箱即用。如果存在真正异步的测试(例如加载的模板),则fakeAsync
会导致有意义的错误,建议将其更改为async
。