مقدمه ای بر جست: تست واحد، تمسخر و کد ناهمزمان

Summarize this content to 400 words in Persian Lang
مقدمه ای بر جست
Jest یک کتابخانه برای آزمایش کد جاوا اسکریپت است.
این یک پروژه منبع باز است که توسط فیس بوک نگهداری می شود، و مخصوصاً برای آزمایش کد React مناسب است، اگرچه محدود به آن نیست: می تواند هر کد جاوا اسکریپت را آزمایش کند. نقاط قوت آن عبارتند از:
سریع است
می تواند تست فوری انجام دهد
این نظرسنجی است، و همه چیز را بدون نیاز به انتخاب شما فراهم می کند
export default function sum(a, n) {
return a + b;
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
divide.test.js
import sum from ‘./sum’;
// Describe the test and wrap it in a function.
it(‘adds 1 + 2 to equal 3’, () => {
const result = sum(1, 2);
// Jest uses matchers, like pretty much any other JavaScript testing framework.
// They’re designed to be easy to get at a glance;
// here, you’re expecting `result` to be 3.
expect(result).toBe(3);
});
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
مسابقات
تطبیق روشی است که به شما امکان می دهد مقادیر را آزمایش کنید.
toBe برابری دقیق را با استفاده از ===
toEqual مقادیر دو متغیر را با هم مقایسه می کند. اگر یک شی یا آرایه باشد، برابری تمام ویژگی ها یا عناصر را بررسی می کند
toBeNull در هنگام ارسال یک مقدار تهی درست است
toBeDefined درست است هنگام ارسال یک مقدار تعریف شده (برخلاف مقدار بالا)
toBeUndefined در هنگام ارسال یک مقدار تعریف نشده درست است
toBeCloseTo برای مقایسه مقادیر شناور، اجتناب از خطاهای گرد کردن استفاده می شود
toBeTruthy درست است اگر مقدار درست در نظر گرفته شود (مانند یک if)
toBeFalsy درست است اگر مقدار نادرست در نظر گرفته شود (مانند یک if)
toBeGreaterThan درست است اگر نتیجه expect() بالاتر از آرگومان باشد
toBeGreaterThanOrEqual درست است اگر نتیجه () expect برابر با آرگومان یا بالاتر از آرگومان باشد
toBeLessThan درست است اگر نتیجه expect() کمتر از آرگومان باشد
toBeLessThanOrEqual درست است اگر نتیجه expect() برابر آرگومان یا کمتر از آرگومان باشد
toMatch برای مقایسه رشته ها با تطبیق الگوی عبارت منظم استفاده می شود
toContain در آرایه ها استفاده می شود، درست است اگر آرایه مورد انتظار حاوی آرگومان در مجموعه عناصر خود باشد
toHaveLength(number): طول یک آرایه را بررسی می کند
toHaveProperty(key, value): بررسی می کند که آیا یک شی دارای ویژگی است یا خیر، و به صورت اختیاری مقدار آن را بررسی می کند
toThrow بررسی می کند که آیا تابعی که پاس می کنید یک استثنا (به طور کلی) یا یک استثنا خاص ایجاد می کند
toBeInstanceOf(): بررسی می کند که آیا یک شی نمونه ای از یک کلاس است
وابستگی ها
وابستگی قطعه کدی است که برنامه شما به آن بستگی دارد. این می تواند یک تابع / شی در پروژه ما یا یک وابستگی شخص ثالث (ex axios) باشد.
یک قطعه کد زمانی به یک وابستگی واقعی تبدیل می شود که برنامه خود شما بدون آن کار نکند.
به عنوان مثال، اگر یک ویژگی را در برنامه خود برای ارسال ایمیل یا درخواست api یا ساخت یک شی پیکربندی و غیره پیاده سازی کنید.
وجود دارد دو راه که ما می توانیم وابستگی هایی را در کد خود در یک پروژه js اضافه کنیم:
واردات
import { name, draw, reportArea, reportPerimeter } from ‘./modules/square.js’;
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
تزریق وابستگی
فقط یک اصطلاح فانتزی در یک مفهوم ساده.
اگر تابع شما نیاز به عملکردی از یک وابستگی خارجی دارد، فقط آن را به عنوان یک آرگومان تزریق کنید.
// Constructor Injection
// DatabaseManager class takes a database connector as a dependency
class DatabaseManager {
constructor(databaseConnector) {
// Dependency injection of the database connector
this.databaseConnector = databaseConnector;
}
updateRow(rowId, data) {
// Use the injected database connector to perform the update
this.databaseConnector.update(rowId, data);
}
}
// parameter injection, takes a database connector instance in as an argument; easy to test!
function updateRow(rowId, data, databaseConnector) {
databaseConnector.update(rowId, data);
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
تست واحد
تستهای واحد توسط توسعهدهندگان نرمافزار نوشته و اجرا میشوند تا اطمینان حاصل کنند که بخشی از یک برنامه (معروف به “واحد”) با طراحی آن مطابقت دارد و مطابق مورد نظر رفتار میکند.
ما می خواهیم کد خود را به صورت مجزا آزمایش کنیم، ما به اجرای واقعی هیچ وابستگی اهمیتی نمی دهیم.ما می خواهیم تأیید کنیم
که واحد کد ما همانطور که انتظار می رود کار می کند
نتایج مورد انتظار را برمی گرداند
هر همکار (وابسته) را همانطور که باید فرا می خواند
و اینجاست که تمسخر وابستگیهای ما وارد عمل میشود.
تمسخر
در تست واحد، ماک ها به ما ارائه می دهند قابلیت خنثی کردن عملکرد ارائه شده توسط یک وابستگی و الف به معنای مشاهده نحوه تعامل کد ما با وابستگی است.
Mock ها به ویژه زمانی مفید هستند که گنجاندن یک وابستگی به طور مستقیم در تست های ما گران یا غیر عملی باشد، به عنوان مثال، در مواردی که کد شما برقراری تماس های HTTP به یک API یا تعامل با لایه پایگاه داده.
ترجیحاً پاسخهای مربوط به این وابستگیها را حذف کنید، در حالی که مطمئن شوید که در صورت لزوم فراخوانی میشوند. اینجاست که مسخره کردن به کار می آید.
با استفاده از توابع ساختگی می توانیم موارد زیر را بدانیم:
را تعداد تماس ها آن را دریافت کرد.
استدلال مقادیر مورد استفاده در هر فراخوانی
را “زمینه” یا این ارزش در هر فراخوانی
نحوه خروج تابع و چه ارزش هایی تولید شد.
تمسخر در شوخی
راه های مختلفی برای ایجاد توابع ساختگی وجود دارد.
را jest.fn متد به ما اجازه می دهد تا به طور مستقیم یک تابع ساختگی جدید ایجاد کنیم.
اگر یک روش شی را مسخره می کنید، می توانید استفاده کنید jest.spyOn.
و اگر می خواهید یک ماژول کامل را مسخره کنید، می توانید استفاده کنید jest.mock.
را jest.fn روش به خودی خود الف است higher-order function.
این یک روش کارخانه ای است که توابع ساختگی جدید و استفاده نشده ایجاد می کند.
توابع در جاوا اسکریپت شهروندان درجه یک هستند، آنها می توانند به عنوان آرگومان منتقل شوند.
هر تابع ساختگی دارای ویژگی های خاصی است. ویژگی ساختگی اساسی است. این ویژگی یک شی است که تمام اطلاعات حالت ساختگی در مورد نحوه فراخوانی تابع را دارد. این شی شامل سه ویژگی آرایه است:
تماس می گیرد [arguments of each call]
موارد [‘this’ value on each call]
نتایج [the value that the function exited]، results دارایی دارد type(بازگشت یا پرتاب) و value
تابع به صراحت یک مقدار را برمی گرداند.
تابع بدون دستور بازگشت (که معادل بازگشت تعریف نشده است) تا پایان کامل می شود
تابع خطا می دهد.
// 1. The mock function factory
function fn(impl = () => {}) {
// 2. The mock function
const mockFn = function(…args) {
// 4. Store the arguments used
mockFn.mock.calls.push(args);
mockFn.mock.instances.push(this);
try {
const value = impl.apply(this, args); // call impl, passing the right this
mockFn.mock.results.push({ type: ‘return’, value });
return value; // return the value
} catch (value) {
mockFn.mock.results.push({ type: ‘throw’, value });
throw value; // re-throw the error
}
}
// 3. Mock state
mockFn.mock = { calls: [], instances: [], results: [] };
return mockFn;
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
Mock Basic
test(“returns undefined by default”, () => {
const mock = jest.fn();
let result = mock(“foo”);
expect(result).toBeUndefined();
expect(mock).toHaveBeenCalled();
expect(mock).toHaveBeenCalledTimes(1);
expect(mock).toHaveBeenCalledWith(“foo”);
});
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
تمسخر وابستگی های تزریقی
const doAdd = (a, b, callback) => {
callback(a + b);
};
test(“calls callback with arguments added”, () => {
const mockCallback = jest.fn();
doAdd(1, 2, mockCallback);
expect(mockCallback).toHaveBeenCalledWith(3);
});
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
ماژول های تمسخر آمیز
تمسخر یک تابع با jest.fn
import * as app from “./app”;
import * as math from “./math”;
math.add = jest.fn();
math.subtract = jest.fn();
test(“calls math.add”, () => {
app.doAdd(1, 2);
expect(math.add).toHaveBeenCalledWith(1, 2);
});
test(“calls math.subtract”, () => {
app.doSubtract(1, 2);
expect(math.subtract).toHaveBeenCalledWith(1, 2);
});
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
این نوع تمسخر به چند دلیل کمتر رایج است:
jest.mock این کار را به طور خودکار برای تمام عملکردهای یک ماژول انجام می دهد
jest.spyOn همین کار را انجام می دهد اما اجازه می دهد تا عملکرد اصلی را بازیابی کنید
با jest.mock یک ماژول را مسخره کنید
یک رویکرد رایج تر استفاده از آن است jest.mock برای تنظیم خودکار تمام صادرات یک ماژول به تابع ساختگی.
import * as app from “./app”;
import * as math from “./math”;
// Set all module functions to jest.fn
jest.mock(“./math.js”);
test(“calls math.add”, () => {
app.doAdd(1, 2);
expect(math.add).toHaveBeenCalledWith(1, 2);
});
test(“calls math.subtract”, () => {
app.doSubtract(1, 2);
expect(math.subtract).toHaveBeenCalledWith(1, 2);
});
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
با jest.spyOn یک تابع را جاسوسی یا مسخره کنید
گاهی اوقات شما فقط می خواهید یک متد فراخوانی را تماشا کنید، اما پیاده سازی اصلی را حفظ کنید. مواقع دیگر ممکن است بخواهید پیاده سازی را مسخره کنید، اما نسخه اصلی را بعداً در مجموعه بازیابی کنید.
import * as app from “./app”;
import * as math from “./math”;
test(“calls math.add”, () => {
const addMock = jest.spyOn(math, “add”);
// calls the original implementation
expect(app.doAdd(1, 2)).toEqual(3);
// and the spy stores the calls to add
expect(addMock).toHaveBeenCalledWith(1, 2);
});
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
پیاده سازی اصلی را بازیابی کنید
// restore the original implementation
addMock.mockRestore();
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
جاوا اسکریپت و حلقه رویداد
جاوا اسکریپت تک رشته ای است: فقط یک کار می تواند در یک زمان اجرا شود. معمولاً این چیز مهمی نیست، اما اکنون تصور کنید که در حال اجرای یک کار هستید که 30 ثانیه طول می کشد. بله.. در طول آن کار، ما 30 ثانیه منتظر می مانیم تا هر اتفاق دیگری رخ دهد (جاوا اسکریپت به طور پیش فرض روی رشته اصلی مرورگر اجرا می شود، بنابراین کل UI گیر کرده است).سال 2020 است، هیچ کس یک وب سایت کند و بدون پاسخ نمی خواهد.
خوشبختانه، مرورگر ویژگی هایی را به ما می دهد که خود موتور جاوا اسکریپت ارائه نمی کند: یک وب API. این شامل DOM API، setTimeout، درخواست های HTTP، و غیره. این می تواند به ما در ایجاد برخی کمک کند ناهمگام، رفتار غیر مسدود کننده
setTimeout(function(){ console.log(“Hello”); }, 3000);
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
پشته تماس بگیرید – وقتی یک تابع را فراخوانی می کنیم، به چیزی به نام پشته تماس اضافه می شود.
WebAPI – setTimeout توسط WebAPI ارائه می شود، یک تابع تماس را دریافت می کند و یک تایمر را بدون مسدود کردن رشته اصلی تنظیم می کند.
صف – هنگامی که تایمر به پایان می رسد، پاسخ به تماس به صف اضافه می شود
حلقه رویداد – بررسی میکند که آیا پشته تماس خالی است، بررسی میکند که آیا تماسهای برگشتی برای اجرا در صف وجود دارد یا خیر، و به پشته تماس برای اجرا میرود.
const foo = () => console.log(“First”);
const bar = () => setTimeout(() => console.log(“Second”), 0);
const baz = () => console.log(“Third”);
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
تست کد ناهمزمان با Jest
Jest معمولاً انتظار دارد که توابع تست ها را اجرا کند به صورت همزمان.
اگر یک عملیات ناهمزمان انجام دهیم، اما به Jest اجازه ندهیم که باید منتظر تمام شدن آزمایش باشد، مثبت کاذب می دهد.
test(“this shouldn’t pass”, () => {
setTimeout(() => {
// this should fail:
expect(false).toBe(true);
});
});
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
الگوهای ناهمزمانالگوهای مختلفی برای مدیریت عملیات ناهمگام در جاوا اسکریپت وجود دارد. پرکاربردترین آنها عبارتند از:
تماس های تلفنی
Promises & Async/Await
تست تماس های تلفنی
شما نمی توانید در یک تماس برگشتی آزمایشی داشته باشید، زیرا Jest آن را اجرا نمی کند – اجرای فایل آزمایشی قبل از فراخوانی پاسخ به پایان می رسد. برای رفع این مشکل، پارامتری را به تابع تست ارسال کنید که به راحتی می توانید آن را فراخوانی کنید done. جست منتظر می ماند تا تماس بگیرید done() قبل از پایان آن آزمون:
//uppercase.js
function uppercase(str, callback) {
callback(str.toUpperCase())
}
module.exports = uppercase
//uppercase.test.js
const uppercase = require(‘./src/uppercase’)
test(`uppercase ‘test’ to equal ‘TEST’`, (done) => {
uppercase(‘test’, (str) => {
expect(str).toBe(‘TEST’)
done()
}
})
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
وعده ها
با توابعی که وعدهها را برمیگردانند، یک وعده را از تست برمیگردانیم:
//uppercase.js
const uppercase = str => {
return new Promise((resolve, reject) => {
if (!str) {
reject(‘Empty string’)
return
}
resolve(str.toUpperCase())
})
}
module.exports = uppercase
//uppercase.test.js
const uppercase = require(‘./uppercase’)
test(`uppercase ‘test’ to equal ‘TEST’`, () => {
return uppercase(‘test’).then(str => {
expect(str).toBe(‘TEST’)
})
})
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
همگام سازی/انتظار
برای آزمایش توابعی که وعدهها را برمیگردانند، میتوانیم از async/wait نیز استفاده کنیم، که نحو را بسیار ساده و ساده میکند:
//uppercase.test.js
const uppercase = require(‘./uppercase’)
test(`uppercase ‘test’ to equal ‘TEST’`, async () => {
const str = await uppercase(‘test’)
expect(str).toBe(‘TEST’)
})
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
نکات
ما باید درک خوبی از عملکردمان داشته باشیم و چه چیزی را می خواهیم آزمایش کنیم
به رفتار کدی که در حال آزمایش آن هستیم فکر کنید
صحنه را تنظیم کنید:
مسخره کردن/جاسوسی از هر گونه وابستگی
آیا کد ما با اشیاء جهانی در تعامل است؟ ما نیز می توانیم آنها را مسخره یا جاسوسی کنیم
آیا تست های ما با DOM تعامل دارند؟ ما می توانیم برخی از عناصر جعلی برای کار با آنها بسازیم
تست های خود را ساختار دهید
با توجه به …
وقتی زنگ میزنم….
بعد … انتظار دارم…..
describe(‘first set’, () => {
beforeEach(() => {
//do something
})
afterAll(() => {
//do something
})
test(/*…*/)
test(/*…*/)
})
describe(‘second set’, () => {
beforeEach(() => {
//do something
})
beforeAll(() => {
//do something
})
test(/*…*/)
test(/*…*/)
})
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
پیوندها
مقدمه ای بر جست
Jest یک کتابخانه برای آزمایش کد جاوا اسکریپت است.
این یک پروژه منبع باز است که توسط فیس بوک نگهداری می شود، و مخصوصاً برای آزمایش کد React مناسب است، اگرچه محدود به آن نیست: می تواند هر کد جاوا اسکریپت را آزمایش کند. نقاط قوت آن عبارتند از:
- سریع است
- می تواند تست فوری انجام دهد
- این نظرسنجی است، و همه چیز را بدون نیاز به انتخاب شما فراهم می کند
export default function sum(a, n) {
return a + b;
}
divide.test.js
import sum from './sum';
// Describe the test and wrap it in a function.
it('adds 1 + 2 to equal 3', () => {
const result = sum(1, 2);
// Jest uses matchers, like pretty much any other JavaScript testing framework.
// They're designed to be easy to get at a glance;
// here, you're expecting `result` to be 3.
expect(result).toBe(3);
});
مسابقات
تطبیق روشی است که به شما امکان می دهد مقادیر را آزمایش کنید.
-
toBe
برابری دقیق را با استفاده از===
-
toEqual
مقادیر دو متغیر را با هم مقایسه می کند. اگر یک شی یا آرایه باشد، برابری تمام ویژگی ها یا عناصر را بررسی می کند -
toBeNull
در هنگام ارسال یک مقدار تهی درست است -
toBeDefined
درست است هنگام ارسال یک مقدار تعریف شده (برخلاف مقدار بالا) -
toBeUndefined
در هنگام ارسال یک مقدار تعریف نشده درست است -
toBeCloseTo
برای مقایسه مقادیر شناور، اجتناب از خطاهای گرد کردن استفاده می شود -
toBeTruthy
درست است اگر مقدار درست در نظر گرفته شود (مانند یک if) -
toBeFalsy
درست است اگر مقدار نادرست در نظر گرفته شود (مانند یک if) -
toBeGreaterThan
درست است اگر نتیجه expect() بالاتر از آرگومان باشد -
toBeGreaterThanOrEqual
درست است اگر نتیجه () expect برابر با آرگومان یا بالاتر از آرگومان باشد -
toBeLessThan
درست است اگر نتیجه expect() کمتر از آرگومان باشد -
toBeLessThanOrEqual
درست است اگر نتیجه expect() برابر آرگومان یا کمتر از آرگومان باشد -
toMatch
برای مقایسه رشته ها با تطبیق الگوی عبارت منظم استفاده می شود -
toContain
در آرایه ها استفاده می شود، درست است اگر آرایه مورد انتظار حاوی آرگومان در مجموعه عناصر خود باشد -
toHaveLength(number)
: طول یک آرایه را بررسی می کند -
toHaveProperty(key, value)
: بررسی می کند که آیا یک شی دارای ویژگی است یا خیر، و به صورت اختیاری مقدار آن را بررسی می کند -
toThrow
بررسی می کند که آیا تابعی که پاس می کنید یک استثنا (به طور کلی) یا یک استثنا خاص ایجاد می کند -
toBeInstanceOf()
: بررسی می کند که آیا یک شی نمونه ای از یک کلاس است
وابستگی ها
وابستگی قطعه کدی است که برنامه شما به آن بستگی دارد. این می تواند یک تابع / شی در پروژه ما یا یک وابستگی شخص ثالث (ex axios) باشد.
یک قطعه کد زمانی به یک وابستگی واقعی تبدیل می شود که برنامه خود شما بدون آن کار نکند.
به عنوان مثال، اگر یک ویژگی را در برنامه خود برای ارسال ایمیل یا درخواست api یا ساخت یک شی پیکربندی و غیره پیاده سازی کنید.
وجود دارد دو راه که ما می توانیم وابستگی هایی را در کد خود در یک پروژه js اضافه کنیم:
واردات
import { name, draw, reportArea, reportPerimeter } from './modules/square.js';
تزریق وابستگی
فقط یک اصطلاح فانتزی در یک مفهوم ساده.
اگر تابع شما نیاز به عملکردی از یک وابستگی خارجی دارد، فقط آن را به عنوان یک آرگومان تزریق کنید.
// Constructor Injection
// DatabaseManager class takes a database connector as a dependency
class DatabaseManager {
constructor(databaseConnector) {
// Dependency injection of the database connector
this.databaseConnector = databaseConnector;
}
updateRow(rowId, data) {
// Use the injected database connector to perform the update
this.databaseConnector.update(rowId, data);
}
}
// parameter injection, takes a database connector instance in as an argument; easy to test!
function updateRow(rowId, data, databaseConnector) {
databaseConnector.update(rowId, data);
}
تست واحد
تستهای واحد توسط توسعهدهندگان نرمافزار نوشته و اجرا میشوند تا اطمینان حاصل کنند که بخشی از یک برنامه (معروف به “واحد”) با طراحی آن مطابقت دارد و مطابق مورد نظر رفتار میکند.
ما می خواهیم کد خود را به صورت مجزا آزمایش کنیم، ما به اجرای واقعی هیچ وابستگی اهمیتی نمی دهیم.
ما می خواهیم تأیید کنیم
- که واحد کد ما همانطور که انتظار می رود کار می کند
- نتایج مورد انتظار را برمی گرداند
- هر همکار (وابسته) را همانطور که باید فرا می خواند
و اینجاست که تمسخر وابستگیهای ما وارد عمل میشود.
تمسخر
در تست واحد، ماک ها به ما ارائه می دهند قابلیت خنثی کردن عملکرد ارائه شده توسط یک وابستگی و الف به معنای مشاهده نحوه تعامل کد ما با وابستگی است.
Mock ها به ویژه زمانی مفید هستند که گنجاندن یک وابستگی به طور مستقیم در تست های ما گران یا غیر عملی باشد، به عنوان مثال، در مواردی که کد شما برقراری تماس های HTTP به یک API یا تعامل با لایه پایگاه داده.
ترجیحاً پاسخهای مربوط به این وابستگیها را حذف کنید، در حالی که مطمئن شوید که در صورت لزوم فراخوانی میشوند. اینجاست که مسخره کردن به کار می آید.
با استفاده از توابع ساختگی می توانیم موارد زیر را بدانیم:
- را تعداد تماس ها آن را دریافت کرد.
- استدلال مقادیر مورد استفاده در هر فراخوانی
- را “زمینه” یا این ارزش در هر فراخوانی
- نحوه خروج تابع و چه ارزش هایی تولید شد.
تمسخر در شوخی
راه های مختلفی برای ایجاد توابع ساختگی وجود دارد.
- را
jest.fn
متد به ما اجازه می دهد تا به طور مستقیم یک تابع ساختگی جدید ایجاد کنیم. - اگر یک روش شی را مسخره می کنید، می توانید استفاده کنید
jest.spyOn
. - و اگر می خواهید یک ماژول کامل را مسخره کنید، می توانید استفاده کنید
jest.mock
.
را jest.fn
روش به خودی خود الف است higher-order function
.
این یک روش کارخانه ای است که توابع ساختگی جدید و استفاده نشده ایجاد می کند.
توابع در جاوا اسکریپت شهروندان درجه یک هستند، آنها می توانند به عنوان آرگومان منتقل شوند.
هر تابع ساختگی دارای ویژگی های خاصی است. ویژگی ساختگی اساسی است. این ویژگی یک شی است که تمام اطلاعات حالت ساختگی در مورد نحوه فراخوانی تابع را دارد. این شی شامل سه ویژگی آرایه است:
- تماس می گیرد [arguments of each call]
- موارد [‘this’ value on each call]
-
نتایج [the value that the function exited]،
results
دارایی داردtype
(بازگشت یا پرتاب) وvalue
- تابع به صراحت یک مقدار را برمی گرداند.
- تابع بدون دستور بازگشت (که معادل بازگشت تعریف نشده است) تا پایان کامل می شود
- تابع خطا می دهد.
// 1. The mock function factory
function fn(impl = () => {}) {
// 2. The mock function
const mockFn = function(...args) {
// 4. Store the arguments used
mockFn.mock.calls.push(args);
mockFn.mock.instances.push(this);
try {
const value = impl.apply(this, args); // call impl, passing the right this
mockFn.mock.results.push({ type: 'return', value });
return value; // return the value
} catch (value) {
mockFn.mock.results.push({ type: 'throw', value });
throw value; // re-throw the error
}
}
// 3. Mock state
mockFn.mock = { calls: [], instances: [], results: [] };
return mockFn;
}
Mock Basic
test("returns undefined by default", () => {
const mock = jest.fn();
let result = mock("foo");
expect(result).toBeUndefined();
expect(mock).toHaveBeenCalled();
expect(mock).toHaveBeenCalledTimes(1);
expect(mock).toHaveBeenCalledWith("foo");
});
تمسخر وابستگی های تزریقی
const doAdd = (a, b, callback) => {
callback(a + b);
};
test("calls callback with arguments added", () => {
const mockCallback = jest.fn();
doAdd(1, 2, mockCallback);
expect(mockCallback).toHaveBeenCalledWith(3);
});
ماژول های تمسخر آمیز
تمسخر یک تابع با jest.fn
import * as app from "./app";
import * as math from "./math";
math.add = jest.fn();
math.subtract = jest.fn();
test("calls math.add", () => {
app.doAdd(1, 2);
expect(math.add).toHaveBeenCalledWith(1, 2);
});
test("calls math.subtract", () => {
app.doSubtract(1, 2);
expect(math.subtract).toHaveBeenCalledWith(1, 2);
});
این نوع تمسخر به چند دلیل کمتر رایج است:
-
jest.mock
این کار را به طور خودکار برای تمام عملکردهای یک ماژول انجام می دهد -
jest.spyOn
همین کار را انجام می دهد اما اجازه می دهد تا عملکرد اصلی را بازیابی کنید
با jest.mock یک ماژول را مسخره کنید
یک رویکرد رایج تر استفاده از آن است jest.mock
برای تنظیم خودکار تمام صادرات یک ماژول به تابع ساختگی.
import * as app from "./app";
import * as math from "./math";
// Set all module functions to jest.fn
jest.mock("./math.js");
test("calls math.add", () => {
app.doAdd(1, 2);
expect(math.add).toHaveBeenCalledWith(1, 2);
});
test("calls math.subtract", () => {
app.doSubtract(1, 2);
expect(math.subtract).toHaveBeenCalledWith(1, 2);
});
با jest.spyOn یک تابع را جاسوسی یا مسخره کنید
گاهی اوقات شما فقط می خواهید یک متد فراخوانی را تماشا کنید، اما پیاده سازی اصلی را حفظ کنید. مواقع دیگر ممکن است بخواهید پیاده سازی را مسخره کنید، اما نسخه اصلی را بعداً در مجموعه بازیابی کنید.
import * as app from "./app";
import * as math from "./math";
test("calls math.add", () => {
const addMock = jest.spyOn(math, "add");
// calls the original implementation
expect(app.doAdd(1, 2)).toEqual(3);
// and the spy stores the calls to add
expect(addMock).toHaveBeenCalledWith(1, 2);
});
پیاده سازی اصلی را بازیابی کنید
// restore the original implementation
addMock.mockRestore();
جاوا اسکریپت و حلقه رویداد
جاوا اسکریپت تک رشته ای است: فقط یک کار می تواند در یک زمان اجرا شود. معمولاً این چیز مهمی نیست، اما اکنون تصور کنید که در حال اجرای یک کار هستید که 30 ثانیه طول می کشد. بله.. در طول آن کار، ما 30 ثانیه منتظر می مانیم تا هر اتفاق دیگری رخ دهد (جاوا اسکریپت به طور پیش فرض روی رشته اصلی مرورگر اجرا می شود، بنابراین کل UI گیر کرده است).
سال 2020 است، هیچ کس یک وب سایت کند و بدون پاسخ نمی خواهد.
خوشبختانه، مرورگر ویژگی هایی را به ما می دهد که خود موتور جاوا اسکریپت ارائه نمی کند: یک وب API. این شامل DOM API، setTimeout، درخواست های HTTP، و غیره. این می تواند به ما در ایجاد برخی کمک کند ناهمگام، رفتار غیر مسدود کننده
setTimeout(function(){ console.log("Hello"); }, 3000);
- پشته تماس بگیرید – وقتی یک تابع را فراخوانی می کنیم، به چیزی به نام پشته تماس اضافه می شود.
- WebAPI – setTimeout توسط WebAPI ارائه می شود، یک تابع تماس را دریافت می کند و یک تایمر را بدون مسدود کردن رشته اصلی تنظیم می کند.
- صف – هنگامی که تایمر به پایان می رسد، پاسخ به تماس به صف اضافه می شود
- حلقه رویداد – بررسی میکند که آیا پشته تماس خالی است، بررسی میکند که آیا تماسهای برگشتی برای اجرا در صف وجود دارد یا خیر، و به پشته تماس برای اجرا میرود.
const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("Second"), 0);
const baz = () => console.log("Third");
تست کد ناهمزمان با Jest
Jest معمولاً انتظار دارد که توابع تست ها را اجرا کند به صورت همزمان.
اگر یک عملیات ناهمزمان انجام دهیم، اما به Jest اجازه ندهیم که باید منتظر تمام شدن آزمایش باشد، مثبت کاذب می دهد.
test("this shouldn't pass", () => {
setTimeout(() => {
// this should fail:
expect(false).toBe(true);
});
});
الگوهای ناهمزمان
الگوهای مختلفی برای مدیریت عملیات ناهمگام در جاوا اسکریپت وجود دارد. پرکاربردترین آنها عبارتند از:
- تماس های تلفنی
- Promises & Async/Await
تست تماس های تلفنی
شما نمی توانید در یک تماس برگشتی آزمایشی داشته باشید، زیرا Jest آن را اجرا نمی کند – اجرای فایل آزمایشی قبل از فراخوانی پاسخ به پایان می رسد. برای رفع این مشکل، پارامتری را به تابع تست ارسال کنید که به راحتی می توانید آن را فراخوانی کنید done
. جست منتظر می ماند تا تماس بگیرید done()
قبل از پایان آن آزمون:
//uppercase.js
function uppercase(str, callback) {
callback(str.toUpperCase())
}
module.exports = uppercase
//uppercase.test.js
const uppercase = require('./src/uppercase')
test(`uppercase 'test' to equal 'TEST'`, (done) => {
uppercase('test', (str) => {
expect(str).toBe('TEST')
done()
}
})
وعده ها
با توابعی که وعدهها را برمیگردانند، یک وعده را از تست برمیگردانیم:
//uppercase.js
const uppercase = str => {
return new Promise((resolve, reject) => {
if (!str) {
reject('Empty string')
return
}
resolve(str.toUpperCase())
})
}
module.exports = uppercase
//uppercase.test.js
const uppercase = require('./uppercase')
test(`uppercase 'test' to equal 'TEST'`, () => {
return uppercase('test').then(str => {
expect(str).toBe('TEST')
})
})
همگام سازی/انتظار
برای آزمایش توابعی که وعدهها را برمیگردانند، میتوانیم از async/wait نیز استفاده کنیم، که نحو را بسیار ساده و ساده میکند:
//uppercase.test.js
const uppercase = require('./uppercase')
test(`uppercase 'test' to equal 'TEST'`, async () => {
const str = await uppercase('test')
expect(str).toBe('TEST')
})
نکات
- ما باید درک خوبی از عملکردمان داشته باشیم و چه چیزی را می خواهیم آزمایش کنیم
- به رفتار کدی که در حال آزمایش آن هستیم فکر کنید
- صحنه را تنظیم کنید:
- مسخره کردن/جاسوسی از هر گونه وابستگی
- آیا کد ما با اشیاء جهانی در تعامل است؟ ما نیز می توانیم آنها را مسخره یا جاسوسی کنیم
- آیا تست های ما با DOM تعامل دارند؟ ما می توانیم برخی از عناصر جعلی برای کار با آنها بسازیم
- تست های خود را ساختار دهید
- با توجه به …
- وقتی زنگ میزنم….
- بعد … انتظار دارم…..
describe('first set', () => {
beforeEach(() => {
//do something
})
afterAll(() => {
//do something
})
test(/*...*/)
test(/*...*/)
})
describe('second set', () => {
beforeEach(() => {
//do something
})
beforeAll(() => {
//do something
})
test(/*...*/)
test(/*...*/)
})
پیوندها