测试具有完整代码覆盖范围的简单记录器功能 [英] Test simple logger functions with full code coverage
问题描述
我正在使用Chai,Sinn和Instanbul来测试NodeJS应用程序.这是 Logger
代码:
I'm using Chai, Sinon and Instanbul to test a NodeJS application. Here's the Logger
code:
import Debug, { IDebugger } from 'debug';
export default class Logger {
private readonly dbg: IDebugger;
constructor(name: string) {
this.dbg = Debug(name);
}
public log(str: string): void {
this.dbg(str);
}
}
这是我开始做的测试:
import * as fs from 'fs';
import sinon from 'sinon';
import { expect } from 'chai';
import Logger from '../../src/utils/Logger';
import Debug from 'debug';
describe('Unit tests for Logger class', () => {
afterEach(() => {
sinon.restore();
});
describe('#constructor', () => {
it('should set logger', () => {
const setLoggerStub = sinon.stub(Logger.prototype, 'log');
const logExample: string = 'test logger'
const logger = new Logger(logExample);
logger.log('test logger')
sinon.assert.calledWithExactly(setLoggerStub, logExample);
});
});
});
代码覆盖率报告如下:
The code coverage report is the following:
我不确定为什么未测试 log
函数,如何对其进行测试,并将构造函数的测试与 log
函数的测试分开?
I'm not sure why the log
function is not tested, how can I test it and separate the test for the constructor and the test for the log
function?
我不确定要测试什么,因为 log
的唯一功能是将字符串传递给 debug
库.在这种情况下应该采取什么方法?
I'm not sure about what to test because the only function of log
is to pass a string to the debug
library. What should be the approach in this scenario?
推荐答案
log
不包括在内,因为它从未被调用,因此您将其与sinon.stub(Logger.prototype,'log')
.
log
isn't covered because it never got called, you stubbed it out with sinon.stub(Logger.prototype, 'log')
.
您当前的实现方式很难测试,因为 Logger
与 Debug
太相关了.在构造函数中创建依赖项实例通常不是一个好主意.
Your current implementation is difficult to test because Logger
is too coupled to Debug
. Creating instances of dependencies in the constructor is generally not a good idea.
如果反转依赖关系,则使 Logger
的构造函数使用 IDebugger
而不是 string
名称:
If you invert the dependency, making Logger
's constructor take an IDebugger
instead of the string
name:
import Debug, { IDebugger } from 'debug';
export default class Logger {
constructor(private readonly dbg: IDebugger) {}
public log(str: string): void {
this.dbg(str);
}
}
然后,当您测试 Logger
时,您可以轻松地注入一个测试加倍项:
then when you test Logger
, you can easily inject a test double:
it("debugs the input", () => {
const debug = sinon.stub();
const logger = new Logger(debug);
const message = "hello, world!";
logger.log(message);
sinon.assert.calledWithExactly(debug, message);
});
这意味着您无需监视 Logger
本身的任何部分,从而使您可以更轻松地在该类中进行重构.现在, Logger
类仅取决于抽象的 IDebugger
接口,而不取决于具体的 Debug
实现.
This means you don't need to spy on any part of Logger
itself, allowing you to refactor inside that class more easily. The Logger
class now only depends on the abstract IDebugger
interface, not the concrete Debug
implementation.
使用给定特定名称的 Debug
创建 Logger
实例可以只是一个函数或静态方法:
Creating a Logger
instance with a Debug
given the specific name can just be a function, or a static method:
export default class Logger {
static withName(name: string) {
return new Logger(Debug(name));
}
/* ... */
}
这篇关于测试具有完整代码覆盖范围的简单记录器功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!