ماذا افعل الان
أقوم حاليًا بإجراء اختبار لتطبيق الكود. تنقطع هذه الاختبارات في كل مرة بعد إعادة البناء ، خاصة في مكونات واجهة المستخدم. نتيجةً لذلك ، أقضي وقتًا طويلاً في البحث في ملفات .test.js
، متابعًا الرقم السحري البالغ 80٪ لـ Test Coverage .
ماذا علي أن أفعل؟
عند كتابة أي نوع من الاختبارات ، بما في ذلك اختبار الوحدة ، يجب أن أقل تفكيرًا في الكود الذي أختبره ، والمزيد حول ما يفعله هذا الكود. هذا يعني كتابة الاختبارات التي تحاكي سلوك المستخدم. حتى في أدنى مستوى.
مثال
تخيل مكون الأكورديون yuy القياسية. عند الضغط عليه ، يتم فتحه أو إغلاقه. يتم تمرير المحتوى إلى المكون children
.

وظائف مكون الاختبار لدينا هي كما يلي:
- يتم نشر الأكورديون 3 الأولى ، كل ما تبقى مغلقة.
- عند النقر فوق الأكورديون ، يتم
publishAccordionAnalytics
الوحدة النمطية publishAccordionAnalytics
، التي تتعقب التحليلات. نحن نستورد هذه الوحدة من حزمة @myProject/analyticsHelpers
- إذا نقر المستخدم على الأكورديون المخفي في الجزء السفلي من التطبيق ، وبعد فتح محتوى الأكورديون ليس في مجال رؤية المستخدم ، يتم تشغيل الرسوم المتحركة وينتقل محتوى المكون إلى الجزء المرئي من الشاشة.
... import { publishAccordeonAnalytics } from '@myProject/analyticsHelpers'; class Accordion extends Component { positionReference: RefObjectType; constructor(props) { super(props); this.positionReference = React.createRef(); } scrollToRef = (ref) => { const wrapper = document.querySelector('.app'); return isInViewPort(ref, wrapper) ? null : setTimeout(() => { return ref.current && wrapper && wrapper.scrollTo(wrapper.scrollTop, wrapper.scrollTop + ref.current.offsetTop) }, 300); }; render() { const { headerName, children, index } = this.props; const { scrollToRef, positionReference } = this; const defaultOpenAccordions = index >= 3; return ( <Accordion defaultOpen={!defaultOpenAccordions} headerName={headerName} onChange={(open) => { publishAccordionAnalytics(open, headerName); if (defaultOpenAccordions) { scrollToRef(positionReference); } }} id={headerName} > {children} {defaultOpenAccordions && <div data-testId="referenced-div" ref={positionReference} />} </Accordion> ); } }
كيف سأكتب اختبار الآن:
jest.mock('@myProject/analyticsHelpers'); describe('', () => { test(' ', () => { const jsx = ( <Accordion headerName=" "> <div>Test</div> </Accordion> ); const tree = renderer .create(jsx) .toJSON(); expect(tree).toMatchSnapshot(); }); test(' ', () => { const wrapper = mount( <Accordion headerName=" " index={1}> <div>Test</div> </Accordion> ); wrapper.find('Header').simulate('click'); expect(publishAccordeonAnalytics).toHaveBeenCalledTimes(1); }); test(' scrollToRef ', () => { const wrapper = shallow( <Accordion headerName=" " index={7}> <div>Test</div> </Accordion>); const component = wrapper.instance(); component.scrollToRef = jest.fn(); wrapper.find('Header').simulate('click'); expect(publishAccordeonAnalytics).toHaveBeenCalledTimes(1); expect(component.scrollToRef).toHaveBeenCalled(); }) });
أقوم باختبار بنية المكون باستخدام لقطات ، وكذلك استدعاءات الوظائف عند النقر.
هذا الأكورديون يفي بالكامل بالوظائف المتوقعة وتؤكد الاختبارات ذلك. ولكن الآن سوف أقوم بعملية إعادة البناء ، واستبدل React.Component
functional component
، scrollToRef
مكون scrollToRef
في وظيفة منفصلة.
function Accordion ({ marketName, children, index }) { const positionReference = React.createRef(); const defaultOpenAccordions = index >= config.defaultOpenAccordions; return ( <Accordion defaultOpen={!defaultOpenAccordions} headerName={headerName} onChange={(open) => { publishAccordeonAnalytics(open, marketName); if (defaultOpenAccordions) { scrollToRef(positionReference); } }} id={marketName} > {children} {defaultOpenAccordions && <div data-testId="referenced-div" ref={positionReference} />} </Accordion> ); }
سقطت اختباراتي ... فشل اختبار ' scrollToRef '
لأنه لم تعد وظيفة scrollToRef
طريقة خاصة للمكون. سيحدث نفس الشيء مع اختبار ' '
، لكنه استيراد من الوحدة النمطية ، لذا فقد أصبح الآن ناجحًا.
لكتابة اختبار جيد ، أحتاج إلى فهم كيفية استخدام المستخدم لمكوني. مستخدم:
- العثور على الأكورديون الذي يحتوي على المعلومات التي يحتاجها
- النقر على اسم الأكورديون لفتحه
- قرأت ifna
- الأكورديون مغلقة

أدركت أنه لا يهتم بما يطلق عليه المكون الخاص بي وما ينقر عليه وما إلى ذلك. باتباع هذا المبدأ ، يجب أن أكتب شيئًا مثل هذا:
import '@testing-library/jest-dom/extend-expect'; import { render, fireEvent, screen } from '@testing-library/react'; jest.mock('@myProject/analyticsHelpers'); describe('', () => { test(' ', () => { const child = <div></div>;
الآن لقد استنسخت سلوك المستخدم. لقد وجدت الأكورديون العاشر ، نقرت عليه ، قرأت المحتوى ، أغلقته - هذا كل شيء!
هذا الاختبار أنظف كثيرًا ، ويمكن أن يصمد أمام إعادة البناء ويحاكي تفاعل المستخدم. وكان من الأسهل بالنسبة لي أن أكتبها.
باستخدام هذا النمط ، يمكننا تجنب استخدام instance()
Enzyme الأصلي instance()
، state()
، find('ComponentName')
والوظائف الأخرى التي تختبر تطبيق الكود.
للاختبار الجديد ، اعتدت