如何模拟服务? [英] How to mock service?

查看:24
本文介绍了如何模拟服务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的 LoginComponent 中有登录功能:

登录(){this.loading = true;this.subscription = this.authenticationService.login(this.model.username, this.model.password).订阅(结果 => {this.em.changeNav(1);this.loading = false;this.Auth.setToken(result);this.router.navigate(['/code']);this.subscription.unsubscribe();},错误 =>{this.error = JSON.parse(err._body).error;this.loading = false;});}

this.authenticationService.login 是向 api 发送 http 请求的服务...

测试如下:

it('应该登录', fakeAsync(() => {间谍(组件,'登录');let button = fixture.debugElement.nativeElement.querySelector('button');button.click();//检查登录功能是否被调用fixture.whenStable().then(() => {期望(component.login).toHaveBeenCalled();})}));

如何模拟 this.authenticationService.login 服务并在订阅方法中断言?

编辑

测试:

import { async, ComponentFixture, TestBed, fakeAsync, tick, inject } from '@angular/core/testing';从'@angular/platform-b​​rowser' 导入 { By };从@angular/core"导入{DebugElement};从@angular/forms"导入 { FormsModule, ReactiveFormsModule };从 '@angular/router/testing' 导入 { RouterTestingModule };从 '@angular/router' 导入 {Router};import { Http, Request, RequestOptionsArgs, Response, XHRBackend, RequestOptions, ConnectionBackend, Headers, HttpModule, BaseRequestOptions } from '@angular/http';从 './login.service' 导入 {LoginService};进口 {模拟后端,模拟连接来自'@angular/http/testing';从'../emitter.service'导入{EmitterService};从'../auth-token.service'导入{AuthTokenService};import { LoginComponent } from './login.component';从 'rxjs' 导入 {Observable};描述('登录组件',()=> {让后端:MockBackend;让服务:登录服务;让组件:LoginComponent;让夹具:ComponentFixture;beforeEach(async(() => {类 LoginServiceStub {登录() { }};类路由器存根{导航(网址:字符串){返回网址;}}TestBed.configureTestingModule({声明:[登录组件],进口:[表单模块,Http模块,反应形式模块,路由器测试模块],供应商: [登录服务,发射器服务,身份验证服务,{ 提供:登录服务,使用类:登录服务存根 },//{ 提供:路由器,useClass:RouterStub }]}).compileComponents();}));beforeEach(() => {夹具 = TestBed.createComponent(LoginComponent);组件 = 夹具.componentInstance;夹具.detectChanges();});it('应该创建', () => {期望(组件).toBeTruthy();});it('应该登录并导航到仪表板', fakeAsync(inject([LoginService, Router], (authService: LoginService, router: Router) => {间谍(组件,'登录');let button = fixture.debugElement.nativeElement.querySelector('button');spyOn(authService, 'login').and.returnValue(Observable.of(true));button.click();打钩();期望(component.login).toHaveBeenCalled();期望(component.loading).toBe(false);})));});

问题是组件中的 login 函数永远不会被调用

这是 Html 部分:

< IMG类= 装载-IMG" * ngIf = 加载" SRC =数据:图像/GIF; BASE64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh + QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa + dIAAAh + QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwct​​XXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/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">电子邮件</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 *ngIf="f.submitted && !username.valid" class="help-block">电子邮件是必需的</div>

<div class="form-group" [ngClass]="{ 'has-error': f.submitted && !password.valid }"><label for="password" class="cols-sm-2 control-label">密码</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 *ngIf="f.submitted && !password.valid" class="help-block">需要密码</div>

<div class="form-group"><button id="login" type="submit" class="btn btn-primary">登录</button><div *ngIf="error" style="margin-top: 20px;"class="text-center alert alert-danger">{{error}}</div>

<div class="form-group text-center login-down" ><a routerLink="/register" routerLinkActive="active">立即注册</a><a routerLink="/forgot" routerLinkActive="active">忘记密码</a>

</表单>

解决方案

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

class AuthenticationServiceStub {登录() {}};

然后在 configureTestingModule 中提供:

TestBed.configureTestingModule({声明:[TestComponent],供应商: [{ 提供: AuthenticationService, useClass: AuthenticationServiceStub },{ 提供:路由器,使用类:RouterStub }]})

注入你的测试

inject([AuthenticationService, Router],(authService: AuthenticationService, 路由器: 路由器) =>

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

it('应该记录...', fakeAsync(inject([AuthenticationService, Router]

和模拟 login 方法,如:

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

Plunker 示例

这是整个规范:

describe('欢迎组件测试', () => {让 comp:TestComponent;让夹具: ComponentFixture;让德:调试元素;让 el: HTMLElement;beforeEach(async(() => {类 AuthenticationServiceStub {登录() {}};类路由器存根{navigateByUrl(url: string) { return url;}}TestBed.configureTestingModule({声明:[TestComponent],供应商: [{ 提供: AuthenticationService, useClass: AuthenticationServiceStub },{ 提供:路由器,使用类:RouterStub }]}).compileComponents()}));beforeEach(() => {夹具 = TestBed.createComponent(TestComponent);comp = fixture.componentInstance;de = fixture.debugElement.query(By.css('.login'));el = de.nativeElement;夹具.detectChanges();});it('应该登录并导航到仪表板', fakeAsync(inject([AuthenticationService, Router], (authService: AuthenticationService, router: Router) => {const spy = spyOn(router, 'navigateByUrl');spyOn(authService, 'login').and.returnValue(Observable.of(true));el.click();打钩();const navArgs = spy.calls.first().args[0];期望(navArgs).toBe('/dashboard');})));});

I have login function inside my LoginComponent:

login() {
        this.loading = true;

        this.subscription = this.authenticationService.login(this.model.username, this.model.password)
            .subscribe(result => {
                this.em.changeNav(1);
                this.loading = false;
                this.Auth.setToken(result);
                this.router.navigate(['/code']);
                this.subscription.unsubscribe();
            },
            err => {
                this.error = JSON.parse(err._body).error;
                this.loading = false;
            });


    }

this.authenticationService.login is the service which send http request to api...

Here is the test:

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();
        })

    }));

How can I mock this.authenticationService.login service and assert things in subscribe method?

EDIT

Test:

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);
    })));

});

Problem with this is login function from component is never called When I console.log inside login method in component it display message...

This is Html part:

<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>

解决方案

You can create mock class for service:

class AuthenticationServiceStub {
    login() {}
};

then provide it in configureTestingModule:

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

inject in your test

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

wrap it in async(+whenStable) or fakeAsync(+tick) or use jasmine.done directly for waiting execution of async methods

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

and mock login method like:

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

Plunker Example

Here is the entire spec:

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');
    })));
});

这篇关于如何模拟服务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆