如何模拟服务?

时间:2016-12-17 17:18:31

标签: unit-testing angular angular2-http

我的LoginComponent中有登录功能:

this.authenticationService.login

it('should login', fakeAsync(() => { spyOn(component, 'login'); let button = fixture.debugElement.nativeElement.querySelector('button'); button.click(); //CHECK IF LOGIN FUNCTION CALLED fixture.whenStable().then(() => { expect(component.login).toHaveBeenCalled(); }) })); 是向api发送http请求的服务...

以下是测试:

this.authenticationService.login

我如何模拟import { async, ComponentFixture, TestBed, fakeAsync, tick, inject } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { DebugElement } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { RouterTestingModule } from '@angular/router/testing'; import {Router} from '@angular/router'; import { Http, Request, RequestOptionsArgs, Response, XHRBackend, RequestOptions, ConnectionBackend, Headers, HttpModule, BaseRequestOptions } from '@angular/http'; import {LoginService} from './login.service'; import { MockBackend, MockConnection } from '@angular/http/testing'; import {EmitterService} from '../emitter.service'; import {AuthTokenService} from '../auth-token.service'; import { LoginComponent } from './login.component'; import {Observable} from 'rxjs'; describe('LoginComponent', () => { let backend: MockBackend; let service: LoginService; let component: LoginComponent; let fixture: ComponentFixture<LoginComponent>; beforeEach(async(() => { class LoginServiceStub { login() { } }; class RouterStub { navigate(url: string) { return url; } } TestBed.configureTestingModule({ declarations: [LoginComponent], imports: [ FormsModule, HttpModule, ReactiveFormsModule, RouterTestingModule ], providers: [ LoginService, EmitterService, AuthTokenService, { provide: LoginService, useClass: LoginServiceStub }, // { provide: Router, useClass: RouterStub } ] }) .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(LoginComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); it('Should log in and navigate to dashboard', fakeAsync(inject([LoginService, Router], (authService: LoginService, router: Router) => { spyOn(component, 'login'); let button = fixture.debugElement.nativeElement.querySelector('button'); spyOn(authService, 'login').and.returnValue(Observable.of(true)); button.click(); tick(); expect(component.login).toHaveBeenCalled(); expect(component.loading).toBe(false); }))); }); 服务并在订阅方法中断言?

修改

测试:

login

问题是组件中的login函数从未被调用当我在组件中的<form name="form" class="form-horizontal" (ngSubmit)="f.form.valid && login()" #f="ngForm" novalidate> <img class="loading-img" *ngIf="loading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" /> <div class="form-group" [ngClass]="{ 'has-error': f.submitted && !username.valid }"> <label for="username" class="cols-sm-2 control-label">Email</label> <div class="cols-sm-10"> <div class="input-group"> <span class="input-group-addon"><i class="fa fa-user fa" aria-hidden="true"></i></span> <input type="text" class="form-control" name="username" placeholder="Your email" [(ngModel)]="model.username" #username="ngModel" required /> </div> </div> <div *ngIf="f.submitted && !username.valid" class="help-block">Email is required</div> </div> <div class="form-group" [ngClass]="{ 'has-error': f.submitted && !password.valid }"> <label for="password" class="cols-sm-2 control-label">Password</label> <div class="cols-sm-10"> <div class="input-group"> <span class="input-group-addon"><i class="fa fa-lock fa-lg" aria-hidden="true"></i></span> <input type="password" placeholder="Your password" class="form-control" name="password" [(ngModel)]="model.password" #password="ngModel" required /> </div> </div> <div *ngIf="f.submitted && !password.valid" class="help-block">Password is required</div> </div> <div class="form-group"> <button id="login" type="submit" class="btn btn-primary">Login</button> <div *ngIf="error" style="margin-top: 20px;" class="text-center alert alert-danger">{{error}}</div> </div> <div class="form-group text-center login-down" > <a routerLink="/register" routerLinkActive="active">Register now</a> <a routerLink="/forgot" routerLinkActive="active">Forgot password</a> </div> </form> 方法中的console.log时它显示消息...

这是Html部分:

"The Chihuahua /t\u0283\u026a\u02c8w\u0251\u02d0w\u0251\u02d0/ (Spanish: chihuahue\u00f1o) is the smallest breed of dog"

1 个答案:

答案 0 :(得分:5)

您可以为服务创建模拟类:

class AuthenticationServiceStub {
    login() {}
};

然后在configureTestingModule

中提供
TestBed.configureTestingModule({
  declarations: [TestComponent],
  providers: [
    { provide: AuthenticationService, useClass: AuthenticationServiceStub },
    { provide: Router, useClass: RouterStub }
  ]
})

注入你的测试

inject([AuthenticationService, Router], 
   (authService: AuthenticationService, router: Router) =>

将其打包在异步(+ whenStable)或 fakeAsync (+ tick)或使用 jasmine.done 直接等待执行异步方法

it('Should log...', fakeAsync(inject([AuthenticationService, Router]

和模拟login方法如:

spyOn(authService, 'login').and.returnValue(Observable.of(true) );

<强> Plunker Example

以下是整个规范:

describe('Welcome component tests', () => {
    let comp: TestComponent;
    let fixture: ComponentFixture<TestComponent>;
    let de: DebugElement;
    let el: HTMLElement;

    beforeEach(async(() => {
        class AuthenticationServiceStub {
            login() {}
        };

        class RouterStub {
            navigateByUrl(url: string) { return url; }
        }

        TestBed.configureTestingModule({
            declarations: [TestComponent],
            providers: [
                { provide: AuthenticationService, useClass: AuthenticationServiceStub },
                { provide: Router, useClass: RouterStub }
            ]
        })
        .compileComponents()
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(TestComponent);
        comp = fixture.componentInstance;

        de = fixture.debugElement.query(By.css('.login'));
        el = de.nativeElement;
        fixture.detectChanges();
    });

    it('Should log in and navigate to dashboard', fakeAsync(inject([AuthenticationService, Router], (authService: AuthenticationService, router: Router) => {
        const spy = spyOn(router, 'navigateByUrl');
        spyOn(authService, 'login').and.returnValue(Observable.of(true) );

        el.click();
        tick();
        const navArgs = spy.calls.first().args[0];

        expect(navArgs).toBe('/dashboard');
    })));
});