在单元测试中模拟服务

Mocking a service in unit tests

我正在尝试为组件单元测试模拟服务。 这是我的服务:

@Injectable()
export class LoginService {

    constructor(public http: Http) { }

    getLanguages() {
        return this.http.get('the-url')
                        .map((res: Response) => res.json());
    }

...

注意:我的组件在构造函数中调用此方法(在构造组件时加载语言)。

然后我尝试模拟它:

class MockLoginService {
    getLanguages() {
        return Observable.of(
            [
                {
                    'name': 'English (USA)',
                    'locale': 'en-US'
                },
                {
                    'name': 'Español',
                    'locale': 'es-US'
                }
            ]
        );
    }

我的组件单元测试:

  it('should load languages', inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
        tcb
            .overrideProviders(LoginComponent, [ provide(LoginService, { useClass: MockLoginService })])
            .createAsync(LoginComponent).then((fixture) => {
                let element = fixture.nativeElement;
                let loginInstance = fixture.componentInstance;
                fixture.detectChanges();
                expect(loginInstance._loginService.getLanguages).toHaveBeenCalled();
                expect(element.querySelectorAll('option').length).toBe(5);
            });
    }));

问题:

我看到我的模拟服务被调用并且收到的数据是正确的但是我的 2 个测试被跳过了!这是日志:

angular2-polyfills.js:528 Unhandled Promise rejection: 'expect' was used when there was no current spec, this could be because an asynchronous test timed out ; Zone: ; Task: Promise.then ; Value: Error: 'expect' was used when there was no current spec, this could be because an asynchronous test timed out(…)

我知道服务是异步执行的,测试在某处丢失了。 angular2-polyfills.js:530 错误:未捕获(承诺):错误:在没有当前规范时使用了 'expect',这可能是因为异步测试超时(…)

我用 tick 尝试了 fakeAsync - 没有成功。 提前致谢!

您可以尝试手动实例化您的模拟服务并在 beforeEachProviders 方法回调中设置它

var service = new MockLoginService();

beforeEachProviders(() => [ provide(TestService, { useValue: service })]);

it('should load languages', inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
    tcb
        .createAsync(LoginComponent).then((fixture) => {
            let element = fixture.nativeElement;
            let loginInstance = fixture.componentInstance;
            fixture.detectChanges();

            expect(element.querySelectorAll('option').length).toBe(2);
        });
}));

对我有用。看到这个 plunkr:https://plnkr.co/edit/zTy3Ou?p=preview.