【发布时间】:2021-06-01 14:32:30
【问题描述】:
我有一个简单的 Create-User-Component 想要进行单元测试。
该组件依赖于具有一些方法的 Auth Service,例如“登录、注销”等。
身份验证服务同时导入 AngularFireAuth 和 AngularFireStore。它是处理数据库交互的服务。
问题是我无法运行我的测试,因为我得到一个空注入器错误(如下所示)。
我想模拟任何数据库交互,以便我可以单独测试组件。
我尝试了各种方法,监视 auth 服务,模拟其方法,甚至模拟 firestore 依赖项,但在我面临的特定错误方面没有任何进展。
在下面的代码版本中,我注入了 auth 服务的存根版本,该服务应该在调用其方法之一时进行控制台日志,但不会发生日志记录。
为什么会出现这个错误?如何正确模拟我的 firebase 依赖项以便测试我的组件?
我的代码的最小化示例
组件
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { AuthService } from 'src/app/core/services/auth.service';
@Component({
selector: 'app-create-user',
templateUrl: './create-user.component.html',
styleUrls: ['../credentials.component.scss', './create-user.component.scss'],
})
export class CreateUserComponent {
public createUserForm: FormGroup;
public message: string;
constructor(
private fb: FormBuilder,
private auth: AuthService,
private router: Router
) {
this.createUserForm = this.fb.group({
firstName: ['some name', Validators.required],
lastName: ['some name2', Validators.required],
email: ['some.fake@mail.com', Validators.compose([Validators.required, Validators.email])],
password: ['password123', Validators.required]
});
this.message = '';
}
onSubmit(){
if(!this.createUserForm.valid) {
return;
}
this.auth.createNewUser(this.createUserForm.value)
.then(async () => {
this.router.navigate(['/credentials/verify-email']);
})
.catch(async (e) => console.error(e));
}
}
测试
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { AngularFireModule } from '@angular/fire';
import { AngularFirestoreModule } from '@angular/fire/firestore';
import { FormBuilder, FormsModule } from '@angular/forms';
import { AuthService } from 'src/app/core/services/auth.service';
import { CreateUserComponent } from './create-user.component';
fdescribe('CreateUserComponent', () => {
let component: CreateUserComponent;
let fixture: ComponentFixture<CreateUserComponent>;
let authStub = {
constructor: () => {console.log('constructor called')},
login: () => {console.log('login called')},
logout: () => {console.log('logout called')},
createNewUser: () => {console.log('createNewUser called')},
}
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ CreateUserComponent ],
providers: [ FormBuilder,
{ provide: AuthService, usevalue: authStub},
],
imports: [ FormsModule, AngularFireModule, AngularFirestoreModule ],
}).compileComponents();
fixture = TestBed.createComponent(CreateUserComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
服务
import { Injectable } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/auth';
import { AngularFirestore } from '@angular/fire/firestore';
import { Router } from '@angular/router';
import firebase from 'firebase/app';
import { UserRegistration } from '../types/user.types';
@Injectable({
providedIn: 'root'
})
export class AuthService {
constructor(
private auth: AngularFireAuth,
private firestore: AngularFirestore,
private router: Router
) {
}
login(email: string, password: string): Promise<firebase.auth.UserCredential> {
return this.auth.signInWithEmailAndPassword(email, password);
}
logout() {
this.auth.signOut()
.then(() => this.router.navigate(['/credentials/login']));
}
createNewUser(user: UserRegistration): Promise<void | firebase.auth.UserCredential> {
return this.auth.createUserWithEmailAndPassword(user.email, user.password)
.then((res: firebase.auth.UserCredential) => {
res.user && res.user.sendEmailVerification();
this.firestore.collection('users')
.add({
firstName: user.firstName,
lastName: user.lastName,
email: res.user ? res.user.email : user.email,
createdAt: new Date(),
});
});
}
}
我得到的错误
Chrome 90.0.4430.212 (Windows 10) CreateUserComponent 应该创建失败 失败:R3InjectorError(DynamicTestModule)[AuthService -> AngularFireAuth -> InjectionToken angularfire2.app.options -> InjectionToken angularfire2.app.options]: NullInjectorError:没有 InjectionToken angularfire2.app.options 的提供者! 错误属性:对象({ ngTempTokenPath:null,ngTokenPath:['AuthService','AngularFireAuth','InjectionToken angularfire2.app.options','InjectionToken angularfire2.app.options']}) NullInjectorError:R3InjectorError(DynamicTestModule)[AuthService -> AngularFireAuth -> InjectionToken angularfire2.app.options -> InjectionToken angularfire2.app.options]: NullInjectorError:没有 InjectionToken angularfire2.app.options 的提供者! 在 NullInjector.get (node_modules/@angular/core/ivy_ngcc/fesm2015/core.js:11077:1) 在 R3Injector.get (node_modules/@angular/core/ivy_ngcc/fesm2015/core.js:11243:1) 在 R3Injector.get (node_modules/@angular/core/ivy_ngcc/fesm2015/core.js:11243:1) 在 injectInjectorOnly (node_modules/@angular/core/ivy_ngcc/fesm2015/core.js:4728:1) 在 Module.ɵɵinject (node_modules/@angular/core/ivy_ngcc/fesm2015/core.js:4732:1) 在 Object.AngularFireAuth_Factory [作为工厂] (node_modules/@angular/fire/ivy_ngcc/fesm2015/angular-fire-auth.js:127:152) 在 R3Injector.hydrate (node_modules/@angular/core/ivy_ngcc/fesm2015/core.js:11412:1) 在 R3Injector.get (node_modules/@angular/core/ivy_ngcc/fesm2015/core.js:11232:1) 在 injectInjectorOnly (node_modules/@angular/core/ivy_ngcc/fesm2015/core.js:4728:1) 在 ɵɵinject (node_modules/@angular/core/ivy_ngcc/fesm2015/core.js:4732:1) 错误:预期未定义是真实的。 在 在用户上下文。 (src/app/views/credentials/create-user/create-user.component.spec.ts:35:23) 在 ZoneDelegate.invoke (node_modules/zone.js/fesm2015/zone.js:372:1) 在 ProxyZoneSpec.onInvoke (node_modules/zone.js/fesm2015/zone-testing.js:287:1) Chrome 90.0.4430.212(Windows 10):执行 1 of 37(1 FAILED)(跳过 36)(0.199 秒 / 0.129 秒) 总计:1 次失败,0 次成功
【问题讨论】:
标签: angular typescript firebase unit-testing mocking