使用Jasmine / Karma对组件中的订阅方法进行单元测试

时间:2019-11-19 22:10:35

标签: angular unit-testing jasmine karma-jasmine

我想测试ngOnInit在组件中调用的subscribe方法。此方法称为getPagesJson,在getjsonService中定义,并从JSON文件中获取一个值。

我的测试目标-使用存根为getPagesJson赋一些值,并将其通过测试过程与原始数据进行比较。

订阅单元测试不起作用。 下面的代码:

first-block.component.ts

import { Component, OnInit } from '@angular/core';
import { GetJsonService } from '../../services/get-json.service';

@Component({
  selector: 'app-first-block',
  template: '<h1 class="page-title">{{h1}}</h1>',
  styleUrls: ['./first-block.component.css']  
})

export class FirstBlockComponent implements OnInit {

  h1:any;

  constructor(private getjsonService: GetJsonService) { }

  ngOnInit() {
    this.getjsonService.getPagesJson()
    .subscribe(
      data => this.h1=data["index"][0]["h1"],
      error => console.log(error)
    );
  }
}

get-json.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { HttpErrorResponse } from '@angular/common/http';
import { throwError } from 'rxjs';
import { catchError, retry } from 'rxjs/operators';

import { PagesInt } from '../interfaces/pages-int';

@Injectable({
  providedIn: 'root'
})
export class GetJsonService {

    // Error handler
    private handleError(error: HttpErrorResponse) {
      if (error.error instanceof ErrorEvent) {
        console.error('Error message:', error.error.message);
      } else {  
        console.error(
          `Code from backend ${error.status}, ` +
          `Error: ${error.error}`);
      }
      return throwError(
        'Something is wrong');
    };

    constructor(private http: HttpClient) { }

    getPagesJson() {
      return this.http.get<PagesInt>('/assets/from-server/pages.json')
      .pipe( 
        retry(3), 
        catchError(this.handleError)
      );    
    }     
}

pages-int.ts

export interface PagesInt {
    h1:string;
    videoUrl?:string;
}

first-block.component.spec.ts

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { of, Observable } from "rxjs";

import { FirstBlockComponent } from './first-block.component';
import { GetJsonService } from '../../services/get-json.service';

describe('FirstBlockComponent', () => {
  let component: FirstBlockComponent;
  let fixture: ComponentFixture<FirstBlockComponent>;
  let spy: jasmine.Spy;
  let getjson: GetJsonService;

  const getJsonStub = {
    getPagesJson() {
      const data = [{h1: 'H1 with "Value"'}];
      return of( data );
    }
  };

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ FirstBlockComponent ],
      providers: [ 
        { provide: GetJsonService, useValue: getJsonStub } 
      ]
    })
    .compileComponents();
    getjson = TestBed.get(GetJsonService);
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(FirstBlockComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
// Errors:
// Uncaught TypeError: Cannot read property '0' of undefined thrown


  it('should called getPagesJson', async(() => {
    spy = spyOn(getjson, 'getPagesJson');
    fixture.detectChanges();
    fixture.whenStable().then(() => {
      expect(spy).toBeTruthy(); 
    });
  }));
// Errors:
// Failed: Cannot read property '0' of undefined


// I'm using very simple and non asynchronous approach below
  it('should get H1 by getJsonService.getPagesJson()', () => {
    getjson.getPagesJson(); 
    fixture.detectChanges();
    expect(component.h1).toBe('H1 with "Value"');
  });
// Errors:
// Uncaught TypeError: Cannot read property '0' of undefined thrown
// Expected undefined to be 'H1 with "Value"'.


});

1 个答案:

答案 0 :(得分:0)

测试告诉您出了点问题,这是件好事。您评论中的错误告诉您问题的确切原因。

Cannot read property '0' of undefined表示找不到0未定义。因此,这部分失败了:data["index"][0],并且如果在未定义上找不到0,则data["index"]必须为undefined

first-block.component.ts内,订阅设置了this.h1=data["index"][0]["h1"],然后您在测试中将其嘲笑为const data = [{h1: 'H1 with "Value"'}];。这些不匹配。相反,您应该在测试const data = {index: [{h1: 'H1 with "Value"'}]};内部-这是一个为数据模型创建接口的好机会,因为您遇到了问题。