简体   繁体   中英

How to test observable Angular 2?

I have a simple service

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

@Injectable()
export class TodoService {
    constructor(private http: Http) { }

    getTestData(): Observable<[{}]> {
        return this.http
            .get('https://jsonplaceholder.typicode.com/posts/1')
            .map(res => res.json())
    }
}

and a simple component

import { Component, OnInit} from '@angular/core';
import { TodoService } from './todo.service';

@Component({
    selector: 'todo-component',
    templateUrl: './todo-component.html',
    styleUrls: ['./todo.css']
})

export class TodoComponent implements OnInit {
    testList: Object; 

    constructor(private todoService: TodoService) { }

    ngOnInit() { 
        this.todoService
            .getTestData()
            .subscribe((testList)  => {
                this.testList = testList
            });

    }
}

and I am trying to test this

import { TestBed, async } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { BrowserModule } from '@angular/platform-browser';
import { Observable } from 'rxjs/Observable';

import { TodoComponent } from '../todo.component';
import { TodoService } from '../../todo/todo.service';

let todoService,
    fixture,
    comp,
    todoList = [],
    TodoServiceStub = { 
    getTestData: function() {
        return {
            userId: 1,
            id: 1,
            title: 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit',
            body: `quia et suscipit
                    suscipit recusandae consequuntur expedita et cum
                    reprehenderit molestiae ut ut quas totam
                    nostrum rerum est autem sunt rem eveniet architecto`
        }
    }
},
testDataFromService = { "someKey": "some Val"};

describe('Todo Component', () => {

    beforeEach(async(() => {

       TestBed.configureTestingModule({
           declarations: [ TodoComponent ],
            imports: [
                BrowserModule,
                FormsModule,
                HttpModule
            ],
            providers: [
                {
                    provide: TodoService, useValue: TodoServiceStub
                },
            ],
        })
        .compileComponents()
        .then(() => {
            fixture = TestBed.createComponent(TodoComponent);
            comp = fixture.debugElement.componentInstance;

      todoService = fixture.debugElement.injector.get(TodoService);
            spyOn(todoService, 'getTestData').and.returnValue({ 
            subscribe: () => {} });
        });
    }));

    it('should get data from the http call', async(() => {
        comp.ngOnInit();

        expect(comp.testList).toBe(testDataFromService);
    }))
});

It gets:

Expected undefined to be Object({ someKey: 'some Val' }).

Tried to follow the docs but the comp.testList will be not filled.. If I try to debug this it seems like the service call is being done but in test I can't reach to resolve value.. What am I doing wrong here?

You are missing 2 things.

  1. you didn't mock your service correctly. It should return an Observable and not raw data. Use Observable.of to create an observable with existing data. It also should return an array and not a single object as that is what you defined in your actual service. Be sure to import the operator Observable.of if you do not have some sort of general import file for used rxjs operators.
  2. After init you have to let the Observable return the data before you can check for its presence in the component. Use fakeAsync and tick for this.

Updated code:

import { TestBed, async, tick, fakeAsync } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { BrowserModule } from '@angular/platform-browser';

// if you have not already you should import the Observable.of operator for this test to work
import { Observable } from 'rxjs/Observable';

import { TodoComponent } from '../todo.component';
import { TodoService } from '../../todo/todo.service';

let todoService,
    fixture,
    comp,
    todoList = [],
    TodoServiceStub = { 
    getTestData: function() {
        // return an Observable like you do in your actual service and return an array
        return Observable.of([{
            userId: 1,
            id: 1,
            title: 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit',
            body: `quia et suscipit
                    suscipit recusandae consequuntur expedita et cum
                    reprehenderit molestiae ut ut quas totam
                    nostrum rerum est autem sunt rem eveniet architecto`
        }]);
    }
},
testDataFromService = { "someKey": "some Val"};

describe('Todo Component', () => {

    beforeEach(() => {

       TestBed.configureTestingModule({
           declarations: [ TodoComponent ],
            imports: [
                BrowserModule,
                FormsModule,
                HttpModule
            ],
            providers: [
                {
                    provide: TodoService, useValue: TodoServiceStub
                },
            ],
        })
        .compileComponents()
        .then(() => {
            fixture = TestBed.createComponent(TodoComponent);
            comp = fixture.debugElement.componentInstance;
    }));

    it('should get data from the http call', fakeAsync(() => {
        comp.ngOnInit();

        tick();

        expect(comp.testList).toBe(testDataFromService);
    }))
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM