Angular2单元测试不使用模拟服务
我正在测试一个显示/隐藏登录/退出按钮的非常简单的组件。Angular2单元测试不使用模拟服务
为此我嘲笑我的AuthService
服务,因为它依赖于AngularFire2。
我遇到的问题是出现我的模拟服务(Mock AuthService
)没有被提供来代替实际的AuthService
。
在测试should show the Facebook login button
,service.isAnonymous
预计未定义。在实际的服务中,它是。但在模拟服务是true
。这个测试应该失败。
另外,请注意我正在尝试调用方法service.test(false);
;在模拟服务中,此方法存在并且是public
。但是我收到错误:类型'AuthService'上不存在属性“测试”。
这表明我的模拟服务没有提供。
你可以看到我是如何尝试了两种方式,在我的测试规范提供模拟服务(一个被注释掉):
import { DebugElement } from '@angular/core';
import {
async,
inject,
ComponentFixture,
TestBed
} from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { FacebookLoginComponent } from './facebook-login.component';
import { AuthService } from '../shared/auth.service';
import { MockAuthService } from '../shared/testing/auth.service';
describe('FacebookLoginComponent',() => {
let authService: AuthService;
let component: FacebookLoginComponent;
let fixture: ComponentFixture<FacebookLoginComponent>;
let debugElement: DebugElement;
let htmlElement: HTMLElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FacebookLoginComponent ],
// providers: [{ provide: AuthService, useValue: MockAuthService }]
})
.compileComponents();
TestBed.overrideComponent(FacebookLoginComponent, {
set: {
providers: [{ provide: AuthService, useClass: MockAuthService }]
}
})
}));
beforeEach(() => {
fixture = TestBed.createComponent(FacebookLoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created',() => {
expect(component).toBeTruthy();
});
it('should show the Facebook login button', inject([ AuthService ], (service: AuthService) => {
expect(service.isAnonymous).toBeUndefined();
debugElement = fixture.debugElement.query(By.css('button'));
htmlElement = debugElement.nativeElement;
service.test(false);
expect(htmlElement.textContent).toBe('Facebook Login');
}));
it('should show the Logout button',() => {
debugElement = fixture.debugElement.query(By.css('button'));
htmlElement = debugElement.nativeElement;
expect(htmlElement.textContent).toBe('Logout');
});
});
为了完整;这里是我的模拟服务,MockAuthService
:
import { Injectable } from '@angular/core';
@Injectable()
export class MockAuthService {
public authState: { isAnonymous: boolean, uid: string };
constructor() {
this.authState = { isAnonymous: true, uid: '0HjUd9owxPZ5kibvUCN6S2DgB4x1' };
}
// public get currentUser(): firebase.User {
// return this.authState ? this.authState : undefined;
// }
// public get currentUserObservable(): Observable<firebase.User> {
// return this.afAuth.authState;
// }
public get currentUid(): string {
return this.authState ? this.authState.uid : undefined;
}
public get isAnonymous(): boolean {
return this.authState ? this.authState.isAnonymous : false;
}
public get isAuthenticated(): boolean {
return !!this.authState;
}
// public logout(): void {
// this.afAuth.auth.signOut();
// }
public test(isAnonymous: boolean) {
this.authState.isAnonymous = isAnonymous;
}
}
我不知道如何提供模拟代替。
更新:根据答案和评论到目前为止我有更新我的模拟测试规范
。但是,我仍然有同样的问题。
我得到错误类型'AuthService'上不存在属性'test'。
这表明它仍然没有用实际的authService
服务替代模拟。
而且,当我添加:
public test(test: boolean): boolean {
return test;
}
给实际的服务测试失败;但不是因为上面的错误,而是因为它应该 - 测试的期望没有得到满足。
这是我的最新规范:
import { DebugElement } from '@angular/core';
import {
async,
inject,
ComponentFixture,
TestBed
} from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { FacebookLoginComponent } from './facebook-login.component';
import { AuthService } from '../shared/auth.service';
import { MockAuthService } from '../shared/testing/auth.service';
describe('FacebookLoginComponent',() => {
let authService: AuthService;
let component: FacebookLoginComponent;
let fixture: ComponentFixture<FacebookLoginComponent>;
let debugElement: DebugElement;
let htmlElement: HTMLElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FacebookLoginComponent ],
providers: [{ provide: AuthService, useClass: MockAuthService }]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FacebookLoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created',() => {
expect(component).toBeTruthy();
});
it('should show the Facebook Login button', inject([ AuthService ], (service: AuthService) => {
debugElement = fixture.debugElement.query(By.css('button'));
htmlElement = debugElement.nativeElement;
expect(htmlElement.textContent).toBe('Facebook Login');
}));
it('should show the Logout button', inject([ AuthService ], (service: AuthService) => {
expect(service.isAnonymous).toBe(true);
debugElement = fixture.debugElement.query(By.css('button'));
htmlElement = debugElement.nativeElement;
service.test(false);
fixture.detectChanges();
expect(htmlElement.textContent).toBe('Logout');
}));
});
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FacebookLoginComponent ],
// providers: [{ provide: AuthService, useValue: MockAuthService }]
})
.compileComponents();
TestBed.overrideComponent(FacebookLoginComponent, {
set: {
providers: [{ provide: AuthService, useClass: MockAuthService }]
}
})
}));
有两个问题。 您不需要覆盖组件的提供者,因为您可以在配置TestBed
时提供它们。
我认为你已经开始覆盖组件,因为初始配置不起作用。它不起作用,因为您使用useValue
而不是useClass
。
// providers: [{ provide: AuthService, useValue: MockAuthService }]
这应该这样做:
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FacebookLoginComponent ],
providers: [{ provide: AuthService, useClass: MockAuthService }]
}).compileComponents();
}));
编辑:
使用inject
功能,你应该使用MockAuthService
作为一种类型。 TypeScript应该停止抱怨。
inject([ AuthService ], (service: MockAuthService) => { /* ... */ });
感谢您的建议,但不幸的是,这似乎仍然使用原始(不是模拟)服务,请参阅我的更新问题。 –
我已经更新了我的答案。 –
我可以踢自己,谢谢! –
这是一个类,而不是一个值; 'useClass:MockAuthService'或'useValue:new MockAuthService()'。 – jonrsharpe
谢谢@jonrsharpe,尽管我仍然遇到这个问题,但我已经更新了测试规范。请看我更新的问题。 –
如果你访问'(service作为MockAuthService).test'会怎么样? – jonrsharpe