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 badges1 Answer
Reset to default 2I'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();
});
});