【问题标题】:Angular unit testing. TypeError: Cannot read property 'id' of null. [Jasmine, Karma]角度单元测试。 TypeError:无法读取 null 的属性“id”。 [茉莉,业力]
【发布时间】:2021-08-05 21:40:51
【问题描述】:

我正在为我的 Angular 应用程序编写组件单元测试。我有一个 currentUser 变量,我在我的组件和 html 模板中使用。在每次测试中都会对其进行模拟(通过 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)

下面的代码示例。

user-profile.component.ts

ngOnInit(): void {
    this.currentUser = this.userService.getUser();
    console.log(this.currentUser.id);
    this.userAnnouncements();
  }

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

【问题讨论】:

    标签: javascript angular typescript unit-testing karma-jasmine


    【解决方案1】:

    有一个非常简单的方法可以解决此问题:您可以执行以下操作:

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

    【讨论】:

      【解决方案2】:

      问题是您没有模拟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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-02
        • 2019-04-06
        • 1970-01-01
        • 2013-11-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-06
        相关资源
        最近更新 更多