【问题标题】:How to mock AngularFire 2 service in unit test?如何在单元测试中模拟 AngularFire 2 服务?
【发布时间】:2016-10-28 19:36:47
【问题描述】:

我正在尝试使用 AngularFire 2 auth 为示例 Angular 2 应用程序设置单元测试,该组件相当简单:

import { Component } from '@angular/core';
import { AngularFire, AuthProviders } from 'angularfire2';

@Component({
  moduleId: module.id,
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.css']
})
export class AppComponent {
  isLoggedIn: boolean;

  constructor(public af: AngularFire) {
    this.af.auth.subscribe(auth => {
      if (auth) {
        this.isLoggedIn = true;
      } else {
        this.isLoggedIn = false;
      }
    });
  }

  loginWithFacebook() {
    this.af.auth.login({
      provider: AuthProviders.Facebook
    });
  }

  logout() {
    this.af.auth.logout();
  }
}

我所做的只是围绕 AngularFire 中的 loginlogout 方法,所以我正在考虑使用模拟来检查是否调用了这些方法,但我不确定从哪里开始,我试着做我的规范文件中的以下内容:

import { provide } from '@angular/core';
import { AngularFire } from 'angularfire2';
import {
  beforeEach, beforeEachProviders,
  describe, xdescribe,
  expect, it, xit,
  async, inject
} from '@angular/core/testing';
import { AppComponent } from './app.component';

spyOn(AngularFire, 'auth');

beforeEachProviders(() => [
  AppComponent,
  AngularFire
]);

describe('App Component', () => {
  it('should create the app',
    inject([AppComponent], (app: AppComponent) => {
      expect(app).toBeTruthy();
    })
  );

  it('should log user in',
    inject([AppComponent], (app: AppComponent) => {
      expect(app.fb.auth.login).toHaveBeenCalled();
    })
  );

  it('should log user out',
    inject([AppComponent], (app: AppComponent) => {
      expect(app.fb.auth.logout).toHaveBeenCalled();
    })
  );
});

但是我不确定如何模拟 loginlogout 方法,因为它们是 auth 属性的一部分,有没有办法模拟 auth 以及返回的 loginlogout 方法?

【问题讨论】:

  • 感兴趣的读者应该关注this issue,以减少这方面的痛苦。

标签: unit-testing angular jasmine karma-jasmine angularfire2


【解决方案1】:

在这个sn-p中:

beforeEach(() => addProviders([
  AppComponent,
  AngularFire
]);

您设置(或override)将在您的测试中使用的提供程序。

话虽如此,您可以创建一个不同的类,如果您愿意,可以创建一个模拟类,并使用{ provide: originalClass, useClass: fakeClass } 表示法提供它而不是AngularFire 实际类。

类似这样的:

class AngularFireAuthMock extends AngularFireAuth {           // added this class
  public login() { ... }
  public logout() { ... }
}

class AngularFireMock extends AngularFire {                   // added this class
  public auth: AngularFireAuthMock;
}

beforeEach(() => addProviders([
  AppComponent,
  { provide: AngularFire, useClass: AngularFireMock }         // changed this line
]);

您测试中的AngularFires 将是AngularFireMocks。

【讨论】:

    【解决方案2】:

    希望这不是主题,但我找到了如何模拟 FirebaseDatabase 的最简单的解决方案。

    var object = function() {
          var obj = { valueChanges() {
                return of({data:'data'});     
            }
          }
          return obj;
        }
    
    providers: [..., { provide : AngularFireDatabase,
            useValue: {object : object }} ]
    

    代替 data:'data' 你可以模拟你需要的任何数据。功能可以随意修改。

    【讨论】:

      【解决方案3】:

      类似于@jan,我使用一些实用函数做了一个模拟:

      import {AngularFireAuth} from '@angular/fire/auth';
      import {AngularFireDatabase} from '@angular/fire/database';
      import {auth} from 'firebase/app';
      
      import { Observable, of, Subscription } from 'rxjs';
      
      /**
       * Mocks the Firebase auth by automatically logging in.
       */
      export const AngularFireAuthMock = jasmine.createSpy('signInWithEmailAndPassword')
            .and.returnValue(Promise.resolve({uid: 'fakeuser'}));
      
      /**
       * Mocks an AngularFireDatabase that always returns the given data for any path.
       */
      export function mockAngularFireDatabase(data): AngularFireDatabase {
        return {
          object: (path: string): any => {
            return {
              valueChanges() {
                return of(data);
              }
            }
          }
        } as AngularFireDatabase;
      }
      

      然后你可以像这样在你的规范中使用它们:

       beforeEach(async () => {
          await TestBed.configureTestingModule({
            declarations: [ TweakComponent ],
            imports: [ MatDialogModule, RouterTestingModule ],
            providers: [
             { provide: MAT_DIALOG_DATA, useValue: {} },
             { provide: AngularFireDatabase, useValue: mockAngularFireDatabase({testdata:'hi'})},
             { provide: AngularFireAuth, useValue: AngularFireAuthMock}
           ],
          })
          .compileComponents();
        });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-09-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-23
        • 2020-03-22
        • 1970-01-01
        相关资源
        最近更新 更多