Мокинг зависимостей с помощью сервисов, приводящий к ошибке firebase

Я использую следующий код для имитации зависимости с authservice:

login.component.spec

import { LoginComponent } from "./login.component";
import { ComponentFixture, inject, TestBed } from "@angular/core/testing";
import { async } from "q";
import { MatCardModule } from "@angular/material";
import { AuthService } from "../../services/auth/auth.service";
import { Log } from "@angular/core/testing/src/logger";
import { NO_ERRORS_SCHEMA } from "@angular/core";

class MockAuthService extends AuthService {
  isAuthenticated() {
    return "Mocked";
  }
}

describe("LoginComponent", () => {
  let component: LoginComponent;
  let fixture: ComponentFixture<LoginComponent>;
  let componentService: AuthService;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [LoginComponent],
      providers: [AuthService],
      imports: [MatCardModule]
    });
    TestBed.overrideComponent(LoginComponent, {
      set: { providers: [{ provide: AuthService, useClass: MockAuthService }] }
    });

    fixture = TestBed.createComponent(LoginComponent);
    component = fixture.componentInstance;
    componentService = fixture.debugElement.injector.get(AuthService);
  }));

  it("Service injected via component should be and instance of MockAuthService", () => {
    expect(componentService instanceof MockAuthService).toBeTruthy();
  });
});

login.component

import {Component, OnInit} from '@angular/core';

import {AuthService} from '../../services/auth/auth.service';
import {Router} from '@angular/router';
import {GithubService} from '../../services/github/github.service';
import {Errorcode} from './errorcode.enum';


@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.sass'],

})
export class LoginComponent implements OnInit {
  public loginError: string | boolean = false;

  constructor(public authService: AuthService, public router: Router, private data: GithubService) {
  }

  public signInWithGithub(): void {
    this.authService.loginwithGithubProvider()
      .then(this.loginError = null)
      .catch(err => {
        if (err === Errorcode.FIREBASE_POPUP_CLOSED) {
        this.loginError = 'The popup has been closed before authentication';
        }
        if (err === Errorcode.FIREBASE_REQUEST_EXESS) {
          this.loginError = 'To many requests to the server';
        }
      }
    );
  }

  public logout(): void {
    this.authService.logout();
  }

  ngOnInit() {
  }
}

Но если я посмотрю на результаты, я продолжу получать следующую ошибку:

Error: StaticInjectorError(DynamicTestModule)[AuthService -> AngularFireAuth]: StaticInjectorError(Platform: core)[AuthService -> AngularFireAuth]: NullInjectorError: No provider for AngularFireAuth! in http://localhost:9876/_karma_webpack_/vendor.js (line 59376)

Есть идеи, как я могу это решить?

Подскажите пожалуйста код в login.component.ts?

dmcgrandle 17.12.2018 23:58

@dmcgrandle, конечно, я добавил!

Kevin van Schaijk 18.12.2018 09:23
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
3
2
373
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я воспроизвел вашу проблему в Stackblitz. В настоящее время в Stackblitz все тесты проходят, но вы заметите, что я закомментировал ваше объявление MockAuthService следующим образом:

// class MockAuthService extends AuthService {
//     isAuthenticated() {
//       return "Mocked";
//     }
// }

и заменил его на:

class MockAuthService implements Partial<AuthService> {
    isAuthenticated() {
      return "Mocked";
    }
    loginwithGithubProvider() {
      return new Promise((resolve, reject) => resolve())
    }
    logout() {}
}

Следует отметить ключевое отличие: я заменил extends на implements.

Чтобы воспроизвести свою ошибку, просто закомментируйте мое новое объявление MockAuthService и раскомментируйте исходное. Ошибка, которую вы описали выше, появится снова.

Причина этого в том, что при расширении класса вы получаете все объекты, свойства, методы и т. д. Существующего класса включая конструктор. В вашем случае я совершенно уверен, что конструктор исходного класса AuthService внедрил AngularFireAuth, как и я в Stackblitz в файле support.service.ts, где я реализовал заглушку AuthService. Когда вы расширили класс, а затем внедрили его в TestBed, когда вы переопределили компонент, а затем попытались создать компонент, он попытался выполнить конструктор в этом исходном классе. Однако для AngularFireAuth не был указан поставщик, поэтому он выдал ошибку, которую вы видите. Простое добавление AngularFireAuth в массив поставщиков было бы неправильным решением, потому что вы пытаетесь протестировать компонент, а не службу.

Когда я хочу внедрить фиктивный класс в набор тестов, как вы это сделали здесь, я обычно использую implements, а затем Partial<>, чтобы мне не приходилось реализовывать все методы и свойства исходного класса, и чтобы я только издевался над тем, что я хочу, а не тащил за собой детали реализации исходного класса.

Существует довольно хорошее обсуждение различий между implements и extendsздесь.

Еще несколько примечаний:

  • Мне пришлось добавить еще две имитируемые службы для Router и GithubService. Обратите внимание, что я сделал это как шпион, а не как насмешку над классом обслуживания, просто чтобы показать другой способ сделать это. Я заметил, что вы импортировали NO_ERRORS_SCHEMA, вероятно, чтобы не определять их. Я сам не использую эту схему, хотя она кажется довольно популярной, поскольку я не хочу маскировать ошибки - я бы предпочел, чтобы они были обнаружены и исправлены. :)
  • Я также добавил еще одну спецификацию, чтобы показать, как вы можете сделать следующий шаг, протестировав часть метода signInWithGithub().

Надеюсь, это поможет.

Спасибо! я уверен, что это мне поможет!

Kevin van Schaijk 19.12.2018 09:16

работал отлично! Еще один вопрос, раз уж вы мне так помогли. Как вы можете проверить, установлено ли для loginError определенное сообщение об ошибке после того, как обещание было отклонено?

Kevin van Schaijk 19.12.2018 19:20

@KevinvanSchaijk - не знаю, как я так долго пропустил этот комментарий, приношу свои извинения! Я обновил Stackblitz несколькими примерами того, как тестировать различные значения loginError, возвращаемые из отклоненного обещания. Надеюсь, это все еще помогает. :) Примечание: это также выявило ошибку в том, как вы настроили .then() в компоненте - это должна быть функция, например: подробности .then(() => this.loginError = null) в Stackblitz.

dmcgrandle 30.12.2018 07:02

Другие вопросы по теме