Search code examples
typescriptunit-testingjasminecode-coveragespy

Unit Test With Code coverage using jasmine


I have simple logger .ts file .I am try to do unit test on that .If some one help me to fix my unit test.

logging.service.ts

import 'reflect-metadata'; // Required for tsyringe
import { singleton } from 'tsyringe';
import { Category } from 'typescript-logging';
@singleton()
export class Logger {
private logger: Category;
constructor(){
this.logger = new Category('oidc-security-logger');
}
trace(msg: string): void {
this.logger.trace(msg);
}
debug(msg: string): void {
this.logger.debug(msg);
}
info(msg: string): void {
this.logger.info(msg);
}
warn(msg: string): void {
this.logger.warn(msg);
}
error(msg: string, error?: Error): void {
if(error){
 this.logger.error(msg, error);
 } else {
 this.logger.error(msg, null);
 }
 }
 fatal(msg: string, error?: Error): void {
 if (error) {
   this.logger.fatal(msg, error);
 } else {
      this.logger.fatal(msg, null);
   }
  }
 }

I have tried with following method to complete my unit test. logging.service.spec.ts

import { Logger } from "./logging.service";    

describe("Logger", () => {    
let loggerMok: Logger;    
beforeEach(() => {
 loggerMok = new Logger();
});

it("should be test logger", () => {
const msg='This is for test';
spyOn(loggerMok,'trace').and.stub();
spyOn(loggerMok,'debug').and.stub();
spyOn(loggerMok,'info').and.stub();
spyOn(loggerMok,'warn').and.stub();
spyOn(loggerMok,'error').and.stub();
spyOn(loggerMok,'fatal').and.stub();
loggerMok.trace(msg);
loggerMok.debug(msg);
loggerMok.info(msg);
loggerMok.warn(msg);
loggerMok.error(msg);
loggerMok.fatal(msg);
expect(loggerMok.trace).toHaveBeenCalled();
expect(loggerMok.debug).toHaveBeenCalled();
expect(loggerMok.info).toHaveBeenCalled();
expect(loggerMok.warn).toHaveBeenCalled();
expect(loggerMok.error).toHaveBeenCalled();
expect(loggerMok.fatal).toHaveBeenCalled();

});
});

This unit test is working fine but code coverage is not giving score.


Solution

  • You should be using callThrough instead of stub. When you stub it won't call the actual implementation and basically just ignore the call. Check out Method stubs for more info.

    When you use callThrough it would call the actual implementation thus adding coverage. So you can use something like:

    it("should be test logger", () => {
    const msg='This is for test';
    spyOn(loggerMok,'trace').and.callThrough();
    spyOn(loggerMok,'debug').and.callThrough();
    spyOn(loggerMok,'info').and.callThrough();
    spyOn(loggerMok,'warn').and.callThrough();
    spyOn(loggerMok,'error').and.callThrough();
    spyOn(loggerMok,'fatal').and.callThrough();
    loggerMok.trace(msg);
    loggerMok.debug(msg);
    loggerMok.info(msg);
    loggerMok.warn(msg);
    loggerMok.error(msg);
    loggerMok.fatal(msg);
    expect(loggerMok.trace).toHaveBeenCalled();
    expect(loggerMok.debug).toHaveBeenCalled();
    expect(loggerMok.info).toHaveBeenCalled();
    expect(loggerMok.warn).toHaveBeenCalled();
    expect(loggerMok.error).toHaveBeenCalled();
    expect(loggerMok.fatal).toHaveBeenCalled();
    
    });
    });
    

    But this test case is not very useful since all you do is call it and then check if it's called. Instead I would recommend spying on the new Category and check if that has been called.