【问题标题】:Cannot read property of undefined 'ngOnInit' 'getData'-Angular-Unit testing-jasmine无法读取未定义的“ngOnInit”“getData”的属性-Angular-Unit testing-jasmine
【发布时间】:2019-08-04 13:25:49
【问题描述】:

我正在尝试为订阅服务层中的方法的组件文件编写单元测试

Homecomponent.ts

import { Data } from './../model/data.model';
import { DataService } from './../services/data.service';
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css'],
})
export class HomeComponent implements OnInit {
  data: Data[];
  constructor(private service: DataService) {}

  ngOnInit() {
    this.getData();
  }
  getData() {
    this.service.getData().subscribe(
      (data) => {
        console.log(data);
        this.data = data;
      },
      (err) => {
        console.log(err);
      },
    );
  }
}

HomeComponent.spec.ts

import { Data } from './../model/data.model';
import { HttpClientModule } from '@angular/common/http';
import { HomeComponent } from './home.component';
import { ComponentFixture, async, TestBed } from '@angular/core/testing';
import { DataService } from '../services/data.service';
import { Observable } from 'rxjs';
import 'rxjs/add/observable/of';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { results } from '../model/home';

class MockMyService {
  public data: Data[];
  public getData(): Observable<Data[]> {
    this.data = results;
    return Observable.of(this.data);
  }
}

describe('HomeComponent', () => {
  let component: HomeComponent;
  let fixture: ComponentFixture<HomeComponent>;
  let mockSomeService: MockMyService;
  describe('Async', () => {
    beforeEach(async(() => {
      TestBed.configureTestingModule({
        declarations: [HomeComponent],
        providers: [
          {
            provide: DataService,
            useValue: mockSomeService,
          },
        ],
        imports: [HttpClientModule],
        schemas: [CUSTOM_ELEMENTS_SCHEMA],
      });
      TestBed.compileComponents();
      fixture = TestBed.createComponent(HomeComponent);
      component = fixture.componentInstance;
      fixture.detectChanges();
      mockSomeService = fixture.debugElement.injector.get(DataService);
      spyOn(mockSomeService, 'getData').and.returnValue(Observable.of(results));
      component.ngOnInit();
      fixture.detectChanges();
    }));
  });

  // afterEach(() => {
  //   fixture = undefined;
  // });

  it('method should be called', async () => {
    component.ngOnInit();
    mockSomeService.getData();
    expect(fixture.debugElement.componentInstance.data.length).toEqual(2);
  });
});

如果我使用 组件.ngOnInit(); 它给出了错误

TypeError: Cannot read property 'ngOnInit' of undefined

如果我没有使用 component.ngOnInit() 它给了我错误

TypeError: Cannot read property 'getData' of undefined

我该如何克服这个问题? 提前致谢。

【问题讨论】:

  • 您是否尝试过从 beforeEach 和测试中删除 async
  • @Michal 是的,我试过了,但还是不行:(

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


【解决方案1】:

你已经很近了,但还不够!

  1. 您的 TestBed 配置不得嵌套在其他描述块无法访问的描述块中
  2. 使用模拟服务时,使用术语 useClass: 而不是 useValue:
  3. 在模拟服务时无需监视服务方法
  4. 不要测试您的 ngOnInit,而是测试您的 getData 方法,以确保它正确设置组件上的数据属性。这是因为您不知道 ngOnInit 何时完成异步代码的运行
  5. 由于 getData 是异步的,因此将 done() 回调传递到您的 it 块中,这将允许您在异步代码应该完成时通知测试

另外,您可能使用的是旧版本的 Angular,因为您的 RXJS 版本在版本 6 之前,因为您的代码使用的是 Observable.of() 而不是新语法,即 of()。也许考虑升级!

希望这个解释有所帮助! :)

固定测试代码如下:

class MockMyService {
  public data: Data[];
  public getData(): Observable<Data[]> {
    this.data = results;
    return Observable.of(this.data);
  }
}

describe('HomeComponent', () => {
  let component: HomeComponent;
  let fixture: ComponentFixture<HomeComponent>;
  let dataService: DataService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [HomeComponent],
      providers: [
        {
          provide: DataService,
          useClass: MockMyService
        }
      ],
      imports: [HttpClientModule],
      schemas: [CUSTOM_ELEMENTS_SCHEMA],
    }).compileComponents();
    fixture = TestBed.createComponent(HomeComponent);
    component = fixture.componentInstance;
    dataService = TestBed.get(DataService);
    fixture.detectChanges();
  });

  describe('Given the component is loaded', () => {
    describe('When getData returns mock data', () => {
      it('Then the data attribute has a length of 2', (done) => {
        dataService.getData().subscribe(() => {
          expect(component.data.length).toEqual(2);
          done();
        });
      });
    });
  });
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-27
    • 2018-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-31
    • 2018-12-09
    • 1970-01-01
    相关资源
    最近更新 更多