[英]Angular2 Unit Test Not Using Mock Service
我正在测试一个显示/隐藏登录/退出按钮的非常简单的组件。
为此,我嘲笑我的AuthService
服务,因为它依赖于 AngularFire2。
我遇到的问题是我的模拟服务 ( Mock AuthService
) 似乎没有被提供来代替实际的AuthService
。
在测试中should show the Facebook login button
, service.isAnonymous
应该是未定义的。 在实际服务中,确实如此。 但在模拟服务中是true
。 这个测试应该失败。
另外,请注意我正在尝试调用方法service.test(false);
; 在模拟服务中,此方法存在并且是public
。 但我收到错误:
“AuthService”类型上不存在属性“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, 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”上不存在。
这表明它仍然没有用模拟来代替实际的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) => { /* ... */ });
因此,我在同一个问题上苦苦挣扎并失去了理智。 我的组件中有 2 个服务需要模拟以进行测试。 一个(让我们称之为MyService
)成功地使用了一个模拟,另一个(让我们称之为MyOtherService
)不会使用模拟而是实际的服务。
最终我弄明白了(有点)。 所以这是我正在测试的类/组件:
@Component({
selector: "app-my-component",
templateUrl: "./my-component.component.html",
styleUrls: ["./my-component.component.scss"],
providers: [MyOtherService]
})
export class MyComponentComponent implements OnInit, OnDestroy {
...private logic...
constructor(
private myService: MyService,
private myOtherService: MyOtherService,
private route: ActivatedRoute,
) {}
..component logic...
看到MyOtherService
正在做而MyService
没有做的事情吗?......它在@Component
的提供者中!
事实证明,当我的构造函数中有该服务时,我并不真的需要那里的服务,所以我删除了它,测试开始使用模拟而不是实际服务。
因此,我会检查您是在构造函数中还是在@Component
的提供者中添加服务。
现在,我认为必须有一种方法仍然可以模拟在@Component
的提供者中声明的服务,但我无法弄清楚这一点,而且删除它更容易,因为我的构造函数无论如何都在获取服务。
我知道你的问题很老,但我希望这会有所帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.