پیام های خطای آزمایشی انتزاعات خود را بهبود بخشید

فرض کنید این تست را انجام داده اید:
const add = (a, b) => a + b
if (add(1, 2) !== 4) {
throw new Error('Expected 3 to be 4')
}
(بله، این یک آزمایش است).
اگر این کار را با گره اجرا کنید، در اینجا خروجی قابل انتظار است:
add.test.js:4
throw new Error('Expected 3 to be 4')
^
Error: Expected 3 to be 4
at add.test.js:4:9
at Script.runInThisContext (vm.js:116:20)
at Object.runInThisContext (vm.js:306:38)
at Object. ([stdin]-wrapper:9:26)
at Module._compile (internal/modules/cjs/loader.js:959:30)
at evalScript (internal/process/execution.js:80:25)
at internal/main/eval_stdin.js:29:5
at Socket. (internal/process/execution.js:192:5)
at Socket.emit (events.js:215:7)
at endReadableNT (_stream_readable.js:1184:12)
این یک ردیابی پشته بسیار استاندارد برای این خطا است. پیام واضح است،
اما ما می توانیم بهتر انجام دهیم و انجام می دهیم! اگر همین تست را با Jest بنویسیم، the
خطای حاصل بسیار مفیدتر است:
test('sums numbers', () => {
expect(add(1, 2)).toBe(4)
})
با خطای زیر شکست می خورد:
FAIL ./add.test.js
✕ sums numbers (3 ms)
● sums numbers
expect(received).toBe(expected) // Object.is equality
Expected: 4
Received: 3
2 |
3 | test('sums numbers', () => {
> 4 | expect(add(1, 2)).toBe(4)
| ^
5 | })
6 |
at Object.anonymous> (src/__tests__/add.js:4:21)
در ترمینال حتی بهتر به نظر می رسد:
خوبه درسته مخصوصا اون کد فریم. قادر به دیدن نه تنها خطا
خودت حالا میخواهم چیزها را در اینجا خیالی نگه دارم تا سادهتر بمانم، اما
اینجا با من بمانید چه می شود اگر این جمله را خیلی دوست داشته باشم (یا داشته باشم
مجموعه ای از عبارات) که می خواهم آن را به یک تابع انتزاع کنم، بنابراین من
آیا می توان از آن در یک سری تست های مختلف استفاده کرد؟ بیایید این را امتحان کنیم:
const add = (a, b) => a + b
function assertAdd(inputs, output) {
expect(add(...inputs)).toBe(output)
}
test('sums numbers', () => {
assertAdd([1, 2], 4)
})
لطفا توجه داشته باشید، من هستم نه توصیه می کنم انتزاعات بی فایده ایجاد کنید
مانند مورد بالا مانند هر چیزی، شما باید AHA ها را اعمال کنید
برنامه نویسی (و برای آزمایش).
این پست وبلاگ فقط برای موقعیت هایی مفید است که انتزاع واضح است
و شما می خواهید ادعاهایی را در انتزاع خود بگنجانید.
خوب، با آن انتزاع کوچک، در اینجا خطایی دریافت می کنیم:
FAIL ./add.test.js
✕ sums numbers (3 ms)
● sums numbers
expect(received).toBe(expected) // Object.is equality
Expected: 4
Received: 3
2 |
3 | function assertAdd(inputs, output) {
> 4 | expect(add(...inputs)).toBe(output)
| ^
5 | }
6 |
7 | test('sums numbers', () => {
at assertAdd (add.test.js:4:26)
at Object.anonymous> (add.test.js:8:3)
چی!؟ این نیست تقریبا به عنوان مفید! چه می شد اگر ما یکسری جاهایی که در آن هستیم داشتیم
یک تماس assertAdd? این چارچوب کد چگونه به ما کمک می کند؟ از کجا بدانیم؟
که شکست خورد اوه آن را وجود دارد، من ما انجام دهید دریافت یک خط در ردیابی پشته،
اما… مثل… صحبت از یک قدم به عقب. من ترجیح می دهم آن خط را داشته باشم
نام برد assertAdd همان چیزی باشد که در کادر کد نشان داده شده است.
خوب، هیچ API در Jest برای آن وجود ندارد (هنوز؟)، اما شما می تواند جست را مجبور به دادن کرد
شما قاب را در جایی که می خواهید کد می کنید. چیزی که در ادامه به شما نشان خواهم داد این است که چگونه می توانیم
خروجی این خطا را به صورت زیر در بیاورید:
FAIL ./add.test.js
✕ sums numbers (3 ms)
● sums numbers
expect(received).toBe(expected) // Object.is equality
Expected: 4
Received: 3
14 |
15 | test('sums numbers', () => {
> 16 | assertAdd([1, 2], 4)
| ^
17 | })
18 |
at Object.anonymous> (add.test.js:16:3)
آیا شما علاقه مند هستید؟ باحال بیایید شیرجه بزنیم
در واقع بسیار ساده است. تمام stack trace را که با regular داشتیم به خاطر بسپار
گره؟ خب کی expect کتابخانه خطا می دهد، ما یک ردیابی پشته کامل دریافت می کنیم
همچنین. بیایید مطالب ما را در نظر بگیریم assertAdd عملکرد و آن را در یک
try/catch تا بتوانیم بررسی کنیم error.stack:
function assertAdd(inputs, output) {
try {
expect(add(...inputs)).toBe(output)
} catch (error) {
console.log(error.stack)
throw error
}
}
در اینجا چیزی است که با آن ثبت می شود:
Error: expect(received).toBe(expected) // Object.is equality
Expected: 4
Received: 3
at assertAdd (/Users/kentcdodds/code/kentcdodds.com/add.test.js:5:28)
at Object. (/Users/kentcdodds/code/kentcdodds.com/add.test.js:17:3)
at Object.asyncJestTest (/Users/kentcdodds/code/kentcdodds.com/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:100:37)
at /Users/kentcdodds/code/kentcdodds.com/node_modules/jest-jasmine2/build/queueRunner.js:47:12
at new Promise ()
at mapper (/Users/kentcdodds/code/kentcdodds.com/node_modules/jest-jasmine2/build/queueRunner.js:30:19)
at /Users/kentcdodds/code/kentcdodds.com/node_modules/jest-jasmine2/build/queueRunner.js:77:41
at processTicksAndRejections (internal/process/task_queues.js:93:5)
این error.stack قبلاً یک درمان مفید از Jest’s دریافت کرده است
expect کتابخانه ادعا (حتی در این مرحله رنگ های مفیدی دارد).
به این توجه کنید error.stack در واقع ترکیبی از error.message + روشن
پشته ردیابی تا پیغام خطا که expect تمام موارد فوق را ارائه می دهد
اولین خط “at” که در واقع ردیابی پشته را شروع می کند.
بسیار خوب، پس متوجه خواهید شد که stack trace ما در اینجا بسیار متفاوت از پشته است
جست به ما نشان می دهد این به این دلیل است که بیشتر چیزهای آنجا زیبا هستند
برای توسعه دهندگان بی فایده است. این فقط سر و صدا است. چرا توسعه دهندگان باید این را بدانند
کد آنها پاس شد mapper عملکرد در queueRunner.js:30:19? بله خوشگله
بی ارزش و همینطور
هنگامی که Jest ردیابی پشته را قالب بندی می کند،
آن را
یک سری نویز را فیلتر کنید،
و ما مانده ایم:
Error: expect(received).toBe(expected) // Object.is equality
Expected: 4
Received: 3
at assertAdd (/Users/kentcdodds/code/kentcdodds.com/add.test.js:5:28)
at Object. (/Users/kentcdodds/code/kentcdodds.com/add.test.js:17:3)
قطعا مفیدتره کار بعدی جست این است
ردیف اول را اشغال می کند
در خطوط ردیابی پشته باقی مانده و
چارچوب کد خط اول را ایجاد می کند.
پس از آن
مسیرهای فایل را فرمت می کند
و ما با خطای نسبتاً بی فایده + کدفریم + رد پشته نشان داده شده باقی مانده ایم
بالا
بنابراین، با درک این، راه حل بسیار ساده است: مطمئن شوید که اولی
خط مربوطه در ردیابی پشته ما همان خطی است که در قاب کد می خواهیم!
بنابراین کاری که باید انجام دهیم این است که تابعی را که شامل تابع است فیلتر کنیم
assertAdd و ما خارج از مسابقه هستیم:
function assertAdd(inputs, output) {
try {
expect(add(...inputs)).toBe(output)
} catch (error) {
error.stack = error.stack
// error.stack is a string, so let's split it into lines
.split('\n')
// filter out the line that includes assertAdd (you could make this more robust by using your test utils filename instead).
.filter((line) => !line.includes('assertAdd'))
// join the lines back up into a single (multiline) string
.join('\n')
throw error
}
}
و با آن ما دنباله پشته ای را می گیریم که در بالا با شما آشنا شدم. در اینجا یک
اسکرین شات از این:

مشکل این است که ما واقعاً نمی خواهیم ساده مال ما را فیلتر کنید
سودمندی اگر این تابع کمکی بر روی سایر توابع ساخته شود چه می شود. و همینطور
ما واقعاً می خواهیم حذف کنیم همه چیز فراتر از سودمندی ما همین است
در واقع همان Jest است expect می کند و
استفاده می کند Error.captureStackTrace.
بیایید این را امتحان کنیم:
function assertAdd(inputs, output) {
try {
expect(add(...inputs)).toBe(output)
} catch (error) {
Error.captureStackTrace(error, assertAdd)
throw error
}
}
وای این خیلی تمیزتره پس عبور می کنیم error ما می خواهیم به روز شده و
تابعی که می خواهیم از stack trace حذف شود. این استدلال نامیده می شود
constructorOpt.
طبق اسناد Node.js:
اختیاری constructorOpt آرگومان یک تابع می گیرد. اگر داده شود، همه
قاب ها در بالا constructorOpt، از جمله constructorOpt، حذف خواهد شد
از ردیابی پشته تولید شده.
تقریباً مثل این است که فقط برای استفاده ما ساخته شده است!
بنابراین اینجا همه چیز با هم است:
const add = (a, b) => a + b
function assertAdd(inputs, output) {
try {
expect(add(...inputs)).toBe(output)
} catch (error) {
Error.captureStackTrace(error, assertAdd)
throw error
}
}
test('sums numbers', () => {
assertAdd([1, 2], 4)
})
و این هم خروجی:
FAIL ./add.test.js
✕ sums numbers (3 ms)
● sums numbers
expect(received).toBe(expected) // Object.is equality
Expected: 4
Received: 3
11 |
12 | test('sums numbers', () => {
> 13 | assertAdd([1, 2], 4)
| ^
14 | })
15 |
at Object.anonymous> (add.test.js:13:3)
و این چیزی است که از نظر بصری به نظر می رسد:

نکته دیگری که باید به آن توجه داشت این است که Jest به طور خودکار می داند که کد را قاب نمی کند
از خطی که از آن می آید node_modules. بنابراین اگر شما پست خود را
آب و برق به npm، احتمالاً نیازی به فیلتر کردن چیزها ندارید
خودت این واقعاً فقط برای آن دسته از انتزاعات آزمایشی که پیدا می کنید مفید است
خودتان را در یک بستر آزمایشی در مقیاس بنویسید.
اما دستکاری ردیابی پشته برای پیام های خطای بهبود یافته می تواند خوب باشد
دانشی که باید داشته باشید، حتی برای چیزهایی که در یک رجیستری پست می کنید. برای مثال،
کتابخانه تست DOM این کار را انجام می دهد waitFor
اطمینان حاصل شود که خرابی های ابزار ناهمزمان (مانند find* پرس و جو و
waitFor خود) دارای خطاهای زیبا و ردیابی پشته های معقول است (پشته ناهمگام
آثار بسیار بی فایده هستند).
● waitFor works
TestingLibraryElementError: Unable to find an element with the text: /nothing matches this/. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
body />
2 |
3 | test('waitFor has a nice stack trace', async () => {
> 4 | await waitFor(() => {
| ^
5 | screen.getByText(/nothing matches this/)
6 | })
7 | })
at waitForWrapper (node_modules/@testing-library/dom/dist/wait-for.js:94:27)
at Object.anonymous> (add.test.js:4:9)
امیدوارم این به شما کمک کند تا متوجه شوید که چگونه پیام های خطا را برای آنها بهبود دهید
ابزارهای سفارشی که برای آزمایشات خود می سازید! موفق باشید




