【问题标题】:Testing Error block in subscribe returning observable- Angular-unit testing订阅返回 observable-Angular 单元测试中的测试错误块
【发布时间】:2019-03-14 13:53:29
【问题描述】:

我想测试一个返回 observable 的方法。我可以测试该方法,但我无法涵盖错误返回部分

home.component.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[];
  errorMsg: any;
  constructor(private service: DataService) {}

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

Home.component.spec.ts

import { Data } from './../model/data.model';
import { HttpClientModule } from '@angular/common/http';
import { HomeComponent } from './home.component';
import { ComponentFixture, async, TestBed, fakeAsync } 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 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();
          },
          (err) => {
            expect(component.errorMsg).toEqual(err);
          },
        );
      });
    });
  });
  it('testing error block', () => {
    dataService.getData().subscribe(
      (data) => {},
      (err) => {
      expect(component.errorMsg).toEqual(err);
      },
    );
  });
});

results.model.ts

export const results = [
  {
    effectivefrom: '',
    effectiveto: '',
    externalname: 'SURVEY',
    id: 1,
    jhi_type: '',
    name: ' Survey',
    processstep: 1,
    status: 'Initialization',
  },
  {
    effectivefrom: '',
    effectiveto: '',
    externalname: '',
    id: 2,
    jhi_type: '',
    name: ' Survey',
    processstep: 1,
    status: 'Initialization',
  },
];

我通过了所有测试用例,但我无法覆盖错误块。

返回的错误是对象类型。

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

【问题讨论】:

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


    【解决方案1】:

    在这种情况下,由于您从 ngOnInit() 调用了 this.getData();,因此在从 MockSvc 创建该方法时,您对该方法没有太多控制权。创建 2 个不同的 Mock 服务并使用如下

    试试下面的代码:

    import { Data } from './../model/data.model';
    import { HttpClientModule } from '@angular/common/http';
    import { HomeComponent } from './home.component';
    import { ComponentFixture, async, TestBed, fakeAsync } 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';
    import { ErrorObservable } from 'rxjs/observable/ErrorObservable';
    
    class MockMyService {
        public data: Data[];
        public getData(): Observable<Data[]> {
            this.data = results;
            return Observable.of(this.data);
        }
    }
    
    class MockMyServiceWithError {
        public data: Data[];
        public getData(): Observable<Data[]> {
            this.data = results;
            return new ErrorObservable(this.data);
        }
    }
    
    describe('HomeComponent', () => {
        let component: HomeComponent;
        let fixture: ComponentFixture<HomeComponent>;
        let dataService: DataService;
    
        describe('With Errored Response', () => {
            beforeEach(() => {
                TestBed.configureTestingModule({
                    declarations: [HomeComponent],
                    providers: [
                        {
                            provide: DataService,
                            useClass: MockMyServiceWithError
                        }
                    ],
                    imports: [HttpClientModule],
                    schemas: [CUSTOM_ELEMENTS_SCHEMA]
                }).compileComponents();
                fixture = TestBed.createComponent(HomeComponent);
                component = fixture.componentInstance;
                dataService = TestBed.get(DataService);
                fixture.detectChanges();
            });
            it('should be created',()=>{
                expect(component).toBeDefined();
            })
            it('should have defined error message',()=>{
                expect(component.errorMsg).toBeDefined();
            })
        });
        describe('With Success Response', () => {
            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();
            });
            it('should be created',()=>{
                expect(component).toBeDefined();
            })
            it('should have defined error message',()=>{
                expect(component.errorMsg).toBeUndefined();
            })
        });
    });
    

    另一种方式:

    或者在组件内部将service公开后可能如下所示:

    describe('Given the component is loaded', () => {
            // make constructor(public service: DataService) {}
            it('should expect defined error message',()=>{
                spyOn(compponent.service,'getData').and.returnValue(new ErrorObservable('Error code'));
                component.getData();
                expect(component.errorMsg).toBe('Error code')
            })
            it('should expect getData to be called',()=>{
                spyOn(compponent.service,'getData').and.callThrough();
                component.getData();
                expect(compponent.service.getData).toHaveBeenCalled();
            })
      });
    

    【讨论】:

    • 在添加了它在 MockServiceWithError 中显示的整个代码后它不起作用,返回新的 ErrorObservable is not able to get assigned with this.data 。 error=>“Data[]”类型的参数不能分配给“(this: Observable,subscriber: Subscriber) => TeardownLogic”类型的参数。类型 'Data[]' 不匹配签名 '(this: Observable, subscriber: Subscriber): TeardownLogic'
    • @AnilKumarReddyA :你能分享resultsimport { results } from '../model/home'; 中的数据吗?如果它只是 hard-coded 用于测试目的的模拟对象会很好
    • @AnilKumarReddyA 您是否尝试过另一种方法?另外,您显示的错误似乎是一些type 问题,它是否破坏了测试用例?您可以尝试使用返回类型吗,因为我无法复制此问题
    • 第二种方法也不起作用。我已经在尝试返回不同的数据类型。不工作:(
    • @AnilKumarReddyA wat 是第二种方法的错误吗?它适用于我的情况
    猜你喜欢
    • 2018-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多