如何在不使用额外框架(如 Mocha)的情况下测试 JavaScript 代码?是否可以创建单元测试用例、手动编写测试函数、测试代码等?
我尝试编写一个测试用例,但即使它们位于同一文件夹中,我也无法链接它们。
假设这是 main.js 文件中的一个函数
function calculate(a, b) {
return a + b;
}
这是 testMain.js 文件中的测试用例
function testCalculate(){
if(calculate(1, 1) == 2)
console.log('It Works!');
else
console.log('Test failed');
}
testCalculate();
当我尝试在 IntelliJ IDEA IDE 中运行 testMain.js 时,我收到类似于以下内容的错误
“参考错误:计算未定义”
这取决于您是要测试 Node.js 代码还是前端代码。在这两种情况下,您都必须将被测函数“暴露”给您的测试框架。
Node.js
// main.js
const obj = {};
obj.sum = (a, b) => {
return a+b;
};
module.exports = obj; // Export 'obj' so that it is visible from your test runner
// test.js
const main = require('main.js');
const assert = require('assert');
const it = (desc, fn) => {
try {
fn();
console.log('\x1b[32m%s\x1b[0m', `\u2714 ${desc}`);
} catch (error) {
console.log('\n');
console.log('\x1b[31m%s\x1b[0m', `\u2718 ${desc}`);
console.error(error);
}
};
it('should return the sum of two numbers', () => {
assert.strictEqual(main.sum(5, 10), 15);
});
当您运行
node test.js
时,您应该能够看到测试结果。
前端
// app.js
self.myapp = myapp; // All the methods in myapp will be exposed globally
myapp.sum = function(a, b) {
return a + b;
}
// test.js
function it(desc, fn) {
try {
fn();
console.log('\x1b[32m%s\x1b[0m', '\u2714 ' + desc);
} catch (error) {
console.log('\n');
console.log('\x1b[31m%s\x1b[0m', '\u2718 ' + desc);
console.error(error);
}
}
function assert(condition) {
if (!condition) {
throw new Error();
}
}
it('should return a sum of two integers', function(){
assert(myapp.sum(5, 10) === 15);
});
// test.html - This is your test runner for the front end
<html>
...
<body>
...
<script src="app.js"></script>
<script src="test.js"></script>
</body>
</html>
在浏览器中打开
test.html
,然后打开浏览器控制台。您应该能够看到成功消息。
这样您就可以为 Node.js 和前端 JavaScript 代码编写测试用例,而无需使用 Mocha 或任何其他框架。
为了使您的代码正常工作,您的 testMain.js 文件需要以某种方式导入您的 main.js 代码。
在main.js文件中:
function calculate(a, b) {
return a+b;
}
module.exports.calculate = calculate
在 testMain.js 文件中,导入 main.js:
var main = require('main.js')
function testCalculate(){
if(main.calculate(1+1)==2)
console.log('It Works!');
else
console.log('Test failed');
}
注意:我知道这不一定表现出良好的编码风格,只是为了证明原始问题是什么,对原始片段进行最小的更改
也就是说,通常不值得重新发明轮子并构建自己的测试框架。您能澄清一下您想避免使用现有框架的原因吗?如果您正在寻找简单性,也许像 jstinytest 这样的东西就可以了。
我也在寻找一些解决方案,使我能够在没有外部库的情况下编写简单的测试。这在进行采访或接受采访时特别有用。我需要测试函数是异步的,并且能够使用
done
方法进行回调或基于承诺的测试
下面是我通常复制粘贴到我想要快速测试的文件中的示例。
type Config = {
logPerformance?: boolean;
timeout?: number; // Timeout in milliseconds
};
function createTestRunner(initialConfig?: Config) {
let globalConfig: Config = {
logPerformance: false,
timeout: 5000,
...initialConfig,
};
const assert = {
condition: (condition: boolean, message?: string) => {
if (!condition) {
throw new Error(message || "Assertion failed: condition is false");
}
},
isDeepEqual: (a: any, b: any, message?: string) => {
const stringify1 = JSON.stringify(a);
const stringify2 = JSON.stringify(b);
if (stringify1 !== stringify2) {
throw new Error(
message ||
`Assertion failed: values are not equal ${stringify1} !== ${stringify2}`
);
}
},
shouldThrow: (fn: Function) => {
const message = "Assertion failed: the function hasn't thrown";
try {
fn();
throw new Error(message);
} catch (e) {
if (e instanceof Error && e.message === message) {
throw e;
}
return true;
}
},
};
function setConfig(config: Config) {
globalConfig = { ...globalConfig, ...config };
}
function it(
desc: string,
fn: (done: (error?: any) => void) => void | Promise<void>,
config?: Config
) {
const { logPerformance, timeout } = { ...globalConfig, ...config };
const startTime = Date.now();
const testPromise = executeTestFunction(fn, timeout);
handleTestResult(testPromise, desc, startTime, logPerformance);
}
function executeTestFunction(fn: Function, timeout?: number): Promise<void> {
return new Promise<void>((resolve, reject) => {
let doneCalled = false;
const done = (error?: any) => {
if (doneCalled) {
reject(new Error("done() called multiple times"));
return;
}
doneCalled = true;
if (error) {
reject(error);
} else {
resolve();
}
};
try {
const result = fn.length > 0 ? fn(done) : fn();
if (result instanceof Promise) {
result.then(resolve).catch(reject);
} else if (fn.length === 0 && result === undefined) {
// Synchronous test passed
resolve();
}
if (fn.length > 0 && result === undefined) {
const timeoutDuration = timeout ?? globalConfig.timeout ?? 5000;
setTimeout(() => {
if (!doneCalled) {
reject(new Error("Test timed out: done() was not called"));
}
}, timeoutDuration);
}
} catch (error) {
reject(error);
}
});
}
function handleTestResult(
testPromise: Promise<void>,
desc: string,
startTime: number,
logPerformance?: boolean
) {
testPromise
.then(() => {
logTestSuccess(desc, startTime, logPerformance);
})
.catch((error) => {
logTestFailure(desc, startTime, error, logPerformance);
});
}
function logTestSuccess(
desc: string,
startTime: number,
logPerformance?: boolean
) {
const endTime = Date.now();
let message = `\x1b[32m\u2714 ${desc}\x1b[0m`;
if (logPerformance) {
const duration = endTime - startTime;
message += ` (Duration: ${duration} ms)`;
}
console.log(message);
}
function logTestFailure(
desc: string,
startTime: number,
error: any,
logPerformance?: boolean
) {
const endTime = Date.now();
let message = `\n\x1b[31m\u2718 ${desc}\x1b[0m`;
if (logPerformance) {
const duration = endTime - startTime;
message += ` (Duration: ${duration} ms)`;
}
console.log(message);
console.error(error);
}
// Return the methods
return { it, assert, setConfig };
}
这是使用示例
const { it, assert, setConfig } = createTestRunner({
logPerformance: true,
timeout: 5000,
});
// Synchronous test
it("should add numbers correctly", () => {
const result = 1 + 1;
assert.condition(result === 2, "1 + 1 should equal 2");
});
// Promise-based asynchronous test
it("should resolve after 1 second", () => {
return new Promise<void>((resolve) => {
setTimeout(() => {
assert.condition(true);
resolve();
}, 1000);
});
});
// Callback-based asynchronous test with custom timeout
it(
"should call done after async operation",
(done) => {
setTimeout(() => {
assert.condition(true);
done();
}, 3000);
},
{
timeout: 4000,
}
);
有一个要点,您可以在需要时分叉和使用
我也被同样的问题困扰了一段时间。问题是如何在没有测试框架的情况下测试你的 JavaScript 代码,因为测试框架的工作带来了很多麻烦,而且大多数时候它们都会妨碍。
您可以简单地安装 chai
npm install chai
var should = require('chai').should()
const log = console.log;
//log(should);
//const letters = "abcdef";
const letters = 555;
letters.should.be.a('string');