Angular unit testing. TypeError: Cannot read property 'id' of null. [Jasmine, Karma]
Angular unit testing. TypeError: Cannot read property 'id' of null. [Jasmine, Karma]
我正在为我的 Angular 应用程序编写组件单元测试。我在我的组件和 html 模板中使用了一个 currentUser
变量。它在每次测试中都被模拟(通过 component.currentUser = {...} 硬编码)。无论如何,业力失败了。非常感谢任何帮助。
UserProfileComponent > should create
TypeError: Cannot read property 'id' of null
at UserProfileComponent.ngOnInit (http://localhost:9877/_karma_webpack_/webpack:/src/app/modules/user-profile/page/user-profile/user-profile.component.ts:4:21)
at callHook (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2573:1)
at callHooks (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2542:1)
at executeInitAndCheckHooks (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2493:1)
at refreshView (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9481:1)
at renderComponentOrTemplate (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9580:1)
at tickRootContext (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10811:1)
at detectChangesInRootView (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10836:1)
at RootViewRef.detectChanges (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:22815:1)
at ComponentFixture._tick (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/testing.js:141:1)
下面的代码示例。
用户-profile.component.ts
ngOnInit(): void {
this.currentUser = this.userService.getUser();
console.log(this.currentUser.id);
this.userAnnouncements();
}
用户-profile.component.spec.ts
describe('UserProfileComponent', () => {
let component: UserProfileComponent;
let fixture: ComponentFixture<UserProfileComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HttpClientTestingModule, RouterTestingModule],
declarations: [UserProfileComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(UserProfileComponent);
component = fixture.componentInstance;
component.currentUser = {
id: 1,
email: 'admin@admin.com',
firstname: 'admin',
img_name: 'photo',
lastname: 'admin',
location: 1,
password: 'hashed_pass',
role: 'admin',
username: 'admin',
};
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
问题是您没有模拟 userService
的数据,因此它会覆盖您设置的值。
您应该如下模拟服务:
describe('UserProfileComponent', () => {
let component: UserProfileComponent;
let fixture: ComponentFixture<UserProfileComponent>;
let userService: jasmine.SpyObj<UserService>;
beforeEach(async () => {
const userServiceSpy = jasmine.createSpyObj('UserService', ['getUser']);
await TestBed.configureTestingModule({
imports: [HttpClientTestingModule, RouterTestingModule],
declarations: [UserProfileComponent],
providers: [ {provide: UserService, useValue: userServiceSpy }],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
});
beforeEach(() => {
userService = TestBed.inject(UserService) as jasmine.SpyObj<UserService>;
userService.getUser.and.returnValue({
id: 1,
email: 'admin@admin.com',
firstname: 'admin',
img_name: 'photo',
lastname: 'admin',
location: 1,
password: 'hashed_pass',
role: 'admin',
username: 'admin',
});
fixture = TestBed.createComponent(UserProfileComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
expect(component.currentUser.id).toBe(1)
});
});
我会推荐你阅读the collection of articles to know how to unit test with well defined practice
有一种非常简单的方法可以解决此问题:您可以执行以下操作:
// In your service file, do this:
@Injectable()
class MockUserService extends UserService {
getUser() {
const mockData = {
id: 1,
email: 'admin@admin.com',
firstname: 'admin',
img_name: 'photo',
lastname: 'admin',
location: 1,
password: 'hashed_pass',
role: 'admin',
username: 'admin',
};
return mockData;
}
// You can add more methods your service provides and mock here
}
describe('UserProfileComponent', () => {
let component: UserProfileComponent;
let fixture: ComponentFixture<UserProfileComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HttpClientTestingModule, RouterTestingModule],
declarations: [UserProfileComponent],
providers: [{
provide: UserService,
useClass: MockUserService
}],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(UserProfileComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
expect(component.currentUser.id).toBe(1)
});
it('should run #ngOnInit() method', () => {
spyOn(component, 'ngOnInit').and.callThrough();
component.ngOnInit();
expect(component.ngOnInit).toHaveBeenCalled();
});
});
我正在为我的 Angular 应用程序编写组件单元测试。我在我的组件和 html 模板中使用了一个 currentUser
变量。它在每次测试中都被模拟(通过 component.currentUser = {...} 硬编码)。无论如何,业力失败了。非常感谢任何帮助。
UserProfileComponent > should create
TypeError: Cannot read property 'id' of null
at UserProfileComponent.ngOnInit (http://localhost:9877/_karma_webpack_/webpack:/src/app/modules/user-profile/page/user-profile/user-profile.component.ts:4:21)
at callHook (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2573:1)
at callHooks (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2542:1)
at executeInitAndCheckHooks (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:2493:1)
at refreshView (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9481:1)
at renderComponentOrTemplate (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9580:1)
at tickRootContext (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10811:1)
at detectChangesInRootView (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10836:1)
at RootViewRef.detectChanges (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:22815:1)
at ComponentFixture._tick (http://localhost:9877/_karma_webpack_/webpack:/node_modules/@angular/core/__ivy_ngcc__/fesm2015/testing.js:141:1)
下面的代码示例。
用户-profile.component.ts
ngOnInit(): void {
this.currentUser = this.userService.getUser();
console.log(this.currentUser.id);
this.userAnnouncements();
}
用户-profile.component.spec.ts
describe('UserProfileComponent', () => {
let component: UserProfileComponent;
let fixture: ComponentFixture<UserProfileComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HttpClientTestingModule, RouterTestingModule],
declarations: [UserProfileComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(UserProfileComponent);
component = fixture.componentInstance;
component.currentUser = {
id: 1,
email: 'admin@admin.com',
firstname: 'admin',
img_name: 'photo',
lastname: 'admin',
location: 1,
password: 'hashed_pass',
role: 'admin',
username: 'admin',
};
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
问题是您没有模拟 userService
的数据,因此它会覆盖您设置的值。
您应该如下模拟服务:
describe('UserProfileComponent', () => {
let component: UserProfileComponent;
let fixture: ComponentFixture<UserProfileComponent>;
let userService: jasmine.SpyObj<UserService>;
beforeEach(async () => {
const userServiceSpy = jasmine.createSpyObj('UserService', ['getUser']);
await TestBed.configureTestingModule({
imports: [HttpClientTestingModule, RouterTestingModule],
declarations: [UserProfileComponent],
providers: [ {provide: UserService, useValue: userServiceSpy }],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
});
beforeEach(() => {
userService = TestBed.inject(UserService) as jasmine.SpyObj<UserService>;
userService.getUser.and.returnValue({
id: 1,
email: 'admin@admin.com',
firstname: 'admin',
img_name: 'photo',
lastname: 'admin',
location: 1,
password: 'hashed_pass',
role: 'admin',
username: 'admin',
});
fixture = TestBed.createComponent(UserProfileComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
expect(component.currentUser.id).toBe(1)
});
});
我会推荐你阅读the collection of articles to know how to unit test with well defined practice
有一种非常简单的方法可以解决此问题:您可以执行以下操作:
// In your service file, do this:
@Injectable()
class MockUserService extends UserService {
getUser() {
const mockData = {
id: 1,
email: 'admin@admin.com',
firstname: 'admin',
img_name: 'photo',
lastname: 'admin',
location: 1,
password: 'hashed_pass',
role: 'admin',
username: 'admin',
};
return mockData;
}
// You can add more methods your service provides and mock here
}
describe('UserProfileComponent', () => {
let component: UserProfileComponent;
let fixture: ComponentFixture<UserProfileComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HttpClientTestingModule, RouterTestingModule],
declarations: [UserProfileComponent],
providers: [{
provide: UserService,
useClass: MockUserService
}],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(UserProfileComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
expect(component.currentUser.id).toBe(1)
});
it('should run #ngOnInit() method', () => {
spyOn(component, 'ngOnInit').and.callThrough();
component.ngOnInit();
expect(component.ngOnInit).toHaveBeenCalled();
});
});