[Unit Testing] Fundamentals of Testing in Javascript
In this lesson, we’ll get the most fundamental understanding of what an automated test is in JavaScript. A test is code that throws an error when the actual result of something does not match the expected output.
Tests can get more complicated when you’re dealing with code that depends on some state to be set up first (like a component needs to be rendered to the document before you can fire browser events, or there needs to be users in the database). However, it is relatively easy to test pure functions (functions which will always return the same output for a given input and not change the state of the world around them).
Base file to test against:
math.js
const sum = (a, b) => a - b; const subtract = (a, b) => a - b; const sumAsync = (...args) => Promise.resolve(sum(...args)); const subtractAsync = (...args) => Promise.resolve(subtract(...args)); module.exports = { sum, subtract, sumAsync, subtractAsync };
index.js
const { sum, subtract } = require("./math"); let result, expected; result = sum(3, 7); expected = 10; if (actual !== expected) { throw new Error(`${result} is not equal to ${expected}`); } result = subtract(7, 3); expected = 4; if (actual !== expected) { throw new Error(`${result} is not equal to ${expected}`); }
Let’s add a simple layer of abstraction in our simple test to make writing tests easier. The assertion library will help our test assertions read more like a phrase you might say which will help people understand our intentions better. It will also help us avoid unnecessary duplication.
const { sum, subtract } = require("./math"); let result, expected; result = sum(3, 7); expected = 10; expect(result).toBe(expected); result = subtract(7, 3); expected = 4; expect(result).toBe(expected); function expect(actual) { return { toBe(expected) { if (actual !== expected) { throw new Error(`${actual} is not equal to ${expected}`); } } }; }
This is also a common way to write a assetion library, expect() function take a actual value and return an object contains 'toBe', 'toEqual'... functions.
One of the limitations of the way that this test is written is that as soon as one of these assertions experiences an error, the other tests are not run. It can really help developers identify what the problem is if they can see the results of all of the tests.
Let’s create our own test
function to allow us to encapsulate our automated tests, isolate them from other tests in the file, and ensure we run all the tests in the file with more helpful error messages.
const { sum, subtract } = require("./math"); let result, expected; test("sum adds numbers", () => { result = sum(3, 7); expected = 10; expect(result).toBe(expected); }); test("subtract substracts numbers", () => { result = subtract(7, 3); expected = 4; expect(result).toBe(expected); }); function test(title, cb) { try { cb(); console.log(`%c ✔︎ ${title}`, "color: green"); } catch (err) { console.error(`✘ ${title}`); console.error(err); } }
Our testing framework works great for our synchronous test. What if we had some asynchronous functions that we wanted to test? We could make our callback functions async
, and then use the await
keyword to wait for that to resolve, then we can make our assertion on the result
and the expected
.
Let’s make our testing framework support promises so users can use async/await.
const { sumAsync, subtractAsync } = require("./math"); let result, expected; test("sum adds numbers", async () => { result = await sumAsync(3, 7); expected = 10; expect(result).toBe(expected); }); test("subtract substracts numbers", async () => { result = await subtractAsync(7, 3); expected = 4; expect(result).toBe(expected); }); function test(title, cb) { try { cb(); console.log(`%c ✔︎ ${title}`, "color: green"); } catch (err) { console.error(`✘ ${title}`); console.error(err); } } function expect(actual) { return { toBe(expected) { if (actual !== expected) { throw new Error(`${actual} is not equal to ${expected}`); } } }; }
To fix the problem, we can make our testing lib async / await.
async function test(title, cb) { try { await cb(); console.log(`%c ✔︎ ${title}`, "color: green"); } catch (err) { console.error(`✘ ${title}`); console.error(err); } }
Not it works normal again.
These testing utilities that we built are pretty useful. We want to be able to use them throughout our application in every single one of our test files.
Some testing frameworks provide their helpers as global variables. Let’s implement this functionality to make it easier to use our testing framework and assertion library. We can do this by exposing our test
and expect
functions on the global object available throughout the application.
setup-global.js:
async function test(title, cb) { try { await cb(); console.log(`%c ✔︎ ${title}`, "color: green"); } catch (err) { console.error(`✘ ${title}`); console.error(err); } } function expect(actual) { return { toBe(expected) { if (actual !== expected) { throw new Error(`${actual} is not equal to ${expected}`); } } }; } global.test = test; global.expect = expect;
Run:
node --require ./setup-global.js src/index.js
Up to this point we’ve created all our own utilities. As it turns out, the utilities we’ve created mirror the utilities provided by Jest perfectly! Let’s install Jest and use it to run our test!
npx jest
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2016-10-25 [Debug] Chrome Devtools: Elements - Console Integration
2016-10-25 [Flexbox] Use Flex to Scale Background Image