使用 TestBed 检测服务存根的更改
Detecting changes to service stub using TestBed
这是使用 angular2 文档中提供的存根的 Component
和 Service
的测试示例。
当我尝试构建它并 运行 它时,我发现该组件没有获取第二个测试用例的更改。我总是看到消息。
服务如下所示:
从“@angular/core”导入{可注射};
@Injectable()
export class UserService {
isLoggedIn: true;
user: { name: string };
}
组件如下所示:
import { Component, OnInit } from '@angular/core';
import { UserService } from './user.service';
@Component({
moduleId: module.id,
selector: 'app-welcome',
templateUrl: './welcome.component.html'
})
export class WelcomeComponent implements OnInit {
welcome = '--- not initialized yet';
constructor (private userService: UserService) {}
ngOnInit () {
this.welcome = this.userService.isLoggedIn ?
'Welcome, ' + this.userService.user.name :
'Please log in.';
}
}
这是有问题的单元测试:
import { async, TestBed, ComponentFixture, ComponentFixtureAutoDetect } from '@angular/core/testing';
import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
import { UserService } from './user.service';
import { WelcomeComponent } from './welcome.component';
let fixture: ComponentFixture<WelcomeComponent>;
let comp: WelcomeComponent;
let de: DebugElement;
let el: HTMLElement;
let userService: UserService;
describe('Welcome Component (testing a component with a service)', () => {
beforeEach(async(() => {
const userServiceStub = {
isLoggedIn: true,
user: {
name: 'Test User'
}
};
return TestBed.configureTestingModule({
declarations: [
WelcomeComponent
],
providers: [
{
provide: ComponentFixtureAutoDetect,
useValue: true
},
{
provide: UserService,
useValue: userServiceStub
}
]
}).compileComponents(); // DO NOT USE WITH WEBPACK
}));
beforeEach(() => {
fixture = TestBed.createComponent(WelcomeComponent);
userService = TestBed.get(UserService);
comp = fixture.componentInstance;
de = fixture.debugElement.query(By.css('.welcome'));
el = de.nativeElement;
});
it('should welcome the user', () => {
fixture.detectChanges();
const content = el.textContent;
expect(content).toContain('Welcome', '"Welcome..."');
});
it('should welcome Bubba', () => {
userService.user.name = 'Bubba';
fixture.detectChanges();
expect(el.textContent).toContain('Bubba');
});
});
错误总是:
Expected 'Welcome, Test User' to contain 'Bubba'.
错误:预期 'Welcome, Test User' 包含 'Bubba'。
调试时,我发现服务存根已更新为适当的值。
你在这里做什么
welcome = '--- not initialized yet';
ngOnInit () {
this.welcome = this.userService.isLoggedIn ?
'Welcome, ' + this.userService.user.name :
'Please log in.';
}
只是一次性初始化。对服务的任何后续更新都不会导致重新初始化。
您可以改为使用订阅系统,您可以在其中订阅更新。也许像
welcome = '--- not initialized yet';
ngOnInit () {
this.userService.status$.subscribe(status) => {
let loggedIn = status.isLoggedIn;
let user = status.user;
this.welcome = '...'
})
}
然后您需要更改服务以使用 Subject
或更好的 BehaviorSubject
,您可以在其中发出新值。这些新排放将由组件订阅
class UserService {
private _isLoggedIn: boolean = false;
private _user = { name: 'Anonymous' };
private _status = new BehaviorSubject({
isLoggedIn: this._isLoggedIn
user: this._user
});
get status$() {
return this._status.asObservable();
}
updateUserName(name: string) {
this._user.name = name;
this.emit();
}
updateIsLoggedIn(loggedIn: boolean) {
this.isLoggedIn = loggedIn;
if (!loggedIn) {
this._user.name = 'Anonymous;
}
this.emit();
}
private emit() {
this._status.next({
isLoggedIn: this._isLoggedIn,
user: this._user
})
}
}
使用 Subject
,您可以通过调用 next(..)
发出新值,您传递给它的任何内容都将发送给订阅者。
现在测试中,调用服务即可updateUserName
。如果你想存根测试服务,那么你可以做类似
的事情
let mockService = {
status$: new Subject<>();
}
mockService.status$.next(...)
但实际上,服务是这样的,不使用任何外部依赖项,真的没有必要模拟它。
另请注意,因为现在服务是异步的,您应该使用 async
或 fakeAsync
进行测试,例如
import { fakeAsync, async, tick + from '@angular/core/testing';
it('..', fakeAsync(() => {
service.updateUserName(..)
tick();
expect(...)
}))
it('..', async(() => {
service.updateUserName(..)
fixture.whenStable().then(() => {
expect(...)
})
}))
这是使用 angular2 文档中提供的存根的 Component
和 Service
的测试示例。
当我尝试构建它并 运行 它时,我发现该组件没有获取第二个测试用例的更改。我总是看到消息。
服务如下所示:
从“@angular/core”导入{可注射};
@Injectable()
export class UserService {
isLoggedIn: true;
user: { name: string };
}
组件如下所示:
import { Component, OnInit } from '@angular/core';
import { UserService } from './user.service';
@Component({
moduleId: module.id,
selector: 'app-welcome',
templateUrl: './welcome.component.html'
})
export class WelcomeComponent implements OnInit {
welcome = '--- not initialized yet';
constructor (private userService: UserService) {}
ngOnInit () {
this.welcome = this.userService.isLoggedIn ?
'Welcome, ' + this.userService.user.name :
'Please log in.';
}
}
这是有问题的单元测试:
import { async, TestBed, ComponentFixture, ComponentFixtureAutoDetect } from '@angular/core/testing';
import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
import { UserService } from './user.service';
import { WelcomeComponent } from './welcome.component';
let fixture: ComponentFixture<WelcomeComponent>;
let comp: WelcomeComponent;
let de: DebugElement;
let el: HTMLElement;
let userService: UserService;
describe('Welcome Component (testing a component with a service)', () => {
beforeEach(async(() => {
const userServiceStub = {
isLoggedIn: true,
user: {
name: 'Test User'
}
};
return TestBed.configureTestingModule({
declarations: [
WelcomeComponent
],
providers: [
{
provide: ComponentFixtureAutoDetect,
useValue: true
},
{
provide: UserService,
useValue: userServiceStub
}
]
}).compileComponents(); // DO NOT USE WITH WEBPACK
}));
beforeEach(() => {
fixture = TestBed.createComponent(WelcomeComponent);
userService = TestBed.get(UserService);
comp = fixture.componentInstance;
de = fixture.debugElement.query(By.css('.welcome'));
el = de.nativeElement;
});
it('should welcome the user', () => {
fixture.detectChanges();
const content = el.textContent;
expect(content).toContain('Welcome', '"Welcome..."');
});
it('should welcome Bubba', () => {
userService.user.name = 'Bubba';
fixture.detectChanges();
expect(el.textContent).toContain('Bubba');
});
});
错误总是:
Expected 'Welcome, Test User' to contain 'Bubba'.
错误:预期 'Welcome, Test User' 包含 'Bubba'。
调试时,我发现服务存根已更新为适当的值。
你在这里做什么
welcome = '--- not initialized yet';
ngOnInit () {
this.welcome = this.userService.isLoggedIn ?
'Welcome, ' + this.userService.user.name :
'Please log in.';
}
只是一次性初始化。对服务的任何后续更新都不会导致重新初始化。
您可以改为使用订阅系统,您可以在其中订阅更新。也许像
welcome = '--- not initialized yet';
ngOnInit () {
this.userService.status$.subscribe(status) => {
let loggedIn = status.isLoggedIn;
let user = status.user;
this.welcome = '...'
})
}
然后您需要更改服务以使用 Subject
或更好的 BehaviorSubject
,您可以在其中发出新值。这些新排放将由组件订阅
class UserService {
private _isLoggedIn: boolean = false;
private _user = { name: 'Anonymous' };
private _status = new BehaviorSubject({
isLoggedIn: this._isLoggedIn
user: this._user
});
get status$() {
return this._status.asObservable();
}
updateUserName(name: string) {
this._user.name = name;
this.emit();
}
updateIsLoggedIn(loggedIn: boolean) {
this.isLoggedIn = loggedIn;
if (!loggedIn) {
this._user.name = 'Anonymous;
}
this.emit();
}
private emit() {
this._status.next({
isLoggedIn: this._isLoggedIn,
user: this._user
})
}
}
使用 Subject
,您可以通过调用 next(..)
发出新值,您传递给它的任何内容都将发送给订阅者。
现在测试中,调用服务即可updateUserName
。如果你想存根测试服务,那么你可以做类似
let mockService = {
status$: new Subject<>();
}
mockService.status$.next(...)
但实际上,服务是这样的,不使用任何外部依赖项,真的没有必要模拟它。
另请注意,因为现在服务是异步的,您应该使用 async
或 fakeAsync
进行测试,例如
import { fakeAsync, async, tick + from '@angular/core/testing';
it('..', fakeAsync(() => {
service.updateUserName(..)
tick();
expect(...)
}))
it('..', async(() => {
service.updateUserName(..)
fixture.whenStable().then(() => {
expect(...)
})
}))