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.
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.