最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Angular 6 - Unit testing a subscribe function in constructor - Stack Overflow

programmeradmin0浏览0评论

I've been trying to unit test the subscribe function of this service. And looking at the code coverage report generated by istanbul, I can see that this code is not covered.

Code

layoutponent.ts

import {Component, HostListener, Input} from '@angular/core';

import { LayoutService } from './layout.service';

import { some } from 'lodash';

@Component({
    selector: 'cgm-layout',
    templateUrl: './layoutponent.html',
    styleUrls: ['./layoutponent.scss'],
    providers: [LayoutService]
})
class LayoutComponent {

    message: any;

    constructor(
        private service: LayoutService
    ) {
        service.messagePublished$.subscribe(
            message => {
                this.setMessage(message);
            }
        );
    }

    setMessage(message): void {
        this.message = message;
        setTimeout(() => {
            this.message = null;
        }, 7000);
    }

}

export {
    LayoutComponent
};

This is my Unit Test

layoutponent.spec.ts

import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { of } from 'rxjs';
import { LayoutComponent } from './layoutponent';
import { LayoutService } from './layout.service';

describe('LayoutComponent', () => {
    let ponent: LayoutComponent;
    let fixture: ComponentFixture<LayoutComponent>;
    let service;

    beforeEach(async(() => {
        service = new LayoutService();
        mockLayoutService = jasmine.createSpyObj('LayoutService', ['messagePublished$']);
        TestBed.configureTestingModule({
            declarations: [
                LayoutComponent,

            ],
            providers: [
                LayoutService
            ],
            schemas: [
                NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA
            ]
        })
            pileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(LayoutComponent);
        ponent = fixtureponentInstance;
        fixture.detectChanges();

        ponent.message = 'Garbage';
    });

    it('should call messagePublished', () => {
        spyOn(service.messagePublished$, 'subscribe');
        TestBed.createComponent(LayoutComponent);

        expect(service.messagePublished$.subscribe).toHaveBeenCalled();
    });

    describe('setMessage', () => {

        it('should set the Message', fakeAsync(() => {
            ponent.setMessage('Message');

            expect(ponent.message).toBe('Message');
            tick(7000);
            expect(ponent.message).toBeNull();
        }));

    });
});

So the code never seems to go over the 'service.messagePublished$.subscribe' part. Here is the code coverage report.

The error I'm getting is 'Expected spy subscribe to have been called', which I'm guessing is the error you get when that code block is not covered.

I've been trying to unit test the subscribe function of this service. And looking at the code coverage report generated by istanbul, I can see that this code is not covered.

Code

layout.ponent.ts

import {Component, HostListener, Input} from '@angular/core';

import { LayoutService } from './layout.service';

import { some } from 'lodash';

@Component({
    selector: 'cgm-layout',
    templateUrl: './layout.ponent.html',
    styleUrls: ['./layout.ponent.scss'],
    providers: [LayoutService]
})
class LayoutComponent {

    message: any;

    constructor(
        private service: LayoutService
    ) {
        service.messagePublished$.subscribe(
            message => {
                this.setMessage(message);
            }
        );
    }

    setMessage(message): void {
        this.message = message;
        setTimeout(() => {
            this.message = null;
        }, 7000);
    }

}

export {
    LayoutComponent
};

This is my Unit Test

layout.ponent.spec.ts

import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { of } from 'rxjs';
import { LayoutComponent } from './layout.ponent';
import { LayoutService } from './layout.service';

describe('LayoutComponent', () => {
    let ponent: LayoutComponent;
    let fixture: ComponentFixture<LayoutComponent>;
    let service;

    beforeEach(async(() => {
        service = new LayoutService();
        mockLayoutService = jasmine.createSpyObj('LayoutService', ['messagePublished$']);
        TestBed.configureTestingModule({
            declarations: [
                LayoutComponent,

            ],
            providers: [
                LayoutService
            ],
            schemas: [
                NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA
            ]
        })
            .pileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(LayoutComponent);
        ponent = fixture.ponentInstance;
        fixture.detectChanges();

        ponent.message = 'Garbage';
    });

    it('should call messagePublished', () => {
        spyOn(service.messagePublished$, 'subscribe');
        TestBed.createComponent(LayoutComponent);

        expect(service.messagePublished$.subscribe).toHaveBeenCalled();
    });

    describe('setMessage', () => {

        it('should set the Message', fakeAsync(() => {
            ponent.setMessage('Message');

            expect(ponent.message).toBe('Message');
            tick(7000);
            expect(ponent.message).toBeNull();
        }));

    });
});

So the code never seems to go over the 'service.messagePublished$.subscribe' part. Here is the code coverage report.

The error I'm getting is 'Expected spy subscribe to have been called', which I'm guessing is the error you get when that code block is not covered.

Share edited Nov 13, 2018 at 9:36 Simba3696 asked Nov 12, 2018 at 10:34 Simba3696Simba3696 1611 gold badge1 silver badge8 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 2

I'd advise you to move your subscription from the constructor to an ngOnInit. Angular created several lifecycle hooks which get called when a ponent get's created (ngOnInit) and other when data changes or when it gets destroyed - see Angular lifecycle hooks.

This way you can test your code by calling the ngOnInit() method.

In case you cannot change the code you can try creating a ponent instance and check if your method was called like in pseudo-code below:

import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { of } from 'rxjs';
import { LayoutComponent } from './layout.ponent';
import { LayoutService } from './layout.service';

describe('LayoutComponent', () => {
    let ponent: LayoutComponent;
    let fixture: ComponentFixture<LayoutComponent>;
    let serviceSpy: jasmine.SpyObj<LayoutService>;;

    beforeEach(async(() => {
        const spy = spyOn(service.messagePublished$, 'subscribe')
        TestBed.configureTestingModule({
            declarations: [
                LayoutComponent,

            ],
            providers: [
                { provide: LayoutService, useValue: spy }
            ],
            schemas: [
                NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA
            ]
        })
            .pileComponents();
            serviceSpy = TestBed.get(ValueService);
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(LayoutComponent);
        ponent = fixture.ponentInstance;
        fixture.detectChanges();

        ponent.message = 'Garbage';
    });

    it('should call messagePublished', () => {
        TestBed.createComponent(LayoutComponent);

        expect(service.messagePublished$.subscribe).toHaveBeenCalled();
    });

});
发布评论

评论列表(0)

  1. 暂无评论