Picasso: วิธีทดสอบไลบรารีคอมโพเนนต์

เผยแพร่แล้ว: 2022-03-11

ระบบการออกแบบของ Toptal เวอร์ชันใหม่เพิ่งเปิดตัวเมื่อเร็วๆ นี้ ซึ่งจำเป็นต้องทำการเปลี่ยนแปลงเกือบทุกองค์ประกอบใน Picasso ซึ่งเป็นไลบรารีส่วนประกอบภายในของเรา ทีมของเราต้องเผชิญกับความท้าทาย: เราจะมั่นใจได้อย่างไรว่าการถดถอยจะไม่เกิดขึ้น

คำตอบสั้น ๆ คือการทดสอบค่อนข้างไม่น่าแปลกใจ การทดสอบจำนวนมาก

เราจะไม่ทบทวนแง่มุมทางทฤษฎีของการทดสอบหรือหารือเกี่ยวกับการทดสอบประเภทต่างๆ ประโยชน์ของการทดสอบ หรืออธิบายว่าทำไมคุณควรทดสอบโค้ดของคุณตั้งแต่แรก บล็อกของเราและอื่น ๆ ได้กล่าวถึงหัวข้อเหล่านั้นแล้ว แต่เราจะเน้นเฉพาะด้านการปฏิบัติของการทดสอบเท่านั้น

อ่านเพื่อเรียนรู้วิธีที่นักพัฒนาในการทดสอบการเขียน Toptal พื้นที่เก็บข้อมูลของเราเป็นแบบสาธารณะ ดังนั้นเราจึงใช้ตัวอย่างในโลกแห่งความเป็นจริง ไม่มีนามธรรมหรือการทำให้เข้าใจง่าย

ปิรามิดทดสอบ

เราไม่มีปิรามิดการทดสอบที่กำหนดไว้ ต่อ se แต่ถ้าเราทำจะมีลักษณะดังนี้:

การทดสอบภาพประกอบปิรามิด

ปิรามิดการทดสอบของ Toptal แสดงให้เห็นถึงการทดสอบที่เราเน้น

การทดสอบหน่วย

การทดสอบหน่วยนั้นตรงไปตรงมาในการเขียนและใช้งานง่าย หากคุณมีเวลาน้อยมากในการเขียนแบบทดสอบ พวกเขาควรเป็นตัวเลือกแรกของคุณ

อย่างไรก็ตาม มันไม่สมบูรณ์แบบ ไม่ว่าคุณจะเลือกไลบรารีการทดสอบใด (ในกรณีของเรา Jest และ React Testing Library [RTL]) ไลบรารีนั้นจะไม่มี DOM จริง และจะไม่อนุญาตให้คุณตรวจสอบการทำงานในเบราว์เซอร์ต่างๆ แต่จะอนุญาตให้คุณตัด ขจัดความซับซ้อนและทดสอบหน่วยการสร้างอย่างง่ายของห้องสมุดของคุณ

การทดสอบหน่วยไม่เพียงแต่เพิ่มมูลค่าโดยการทดสอบพฤติกรรมของโค้ด แต่ยังรวมถึงการตรวจสอบความสามารถในการทดสอบโดยรวมของโค้ดด้วย ถ้าคุณไม่สามารถเขียน unit test ได้ง่ายๆ เป็นไปได้ว่าคุณมีโค้ดที่ผิดพลาด

การทดสอบการถดถอยของภาพ

แม้ว่าคุณจะมีความครอบคลุมการทดสอบหน่วย 100% แต่ก็ไม่ได้หมายความว่าส่วนประกอบจะดูดีในอุปกรณ์และเบราว์เซอร์ต่างๆ

การถดถอยของภาพนั้นสังเกตได้ยากเป็นพิเศษด้วยการทดสอบด้วยตนเอง ตัวอย่างเช่น หากป้ายกำกับของปุ่มถูกย้ายไป 1px วิศวกร QA จะสังเกตเห็นหรือไม่ โชคดีที่มีวิธีแก้ไขปัญหาการมองเห็นที่จำกัดนี้มากมาย คุณสามารถเลือกโซลูชันแบบครบวงจรระดับองค์กร เช่น LambdaTest หรือ Mabl คุณสามารถรวมปลั๊กอิน เช่น Percy เข้ากับการทดสอบที่มีอยู่ของคุณ ตลอดจนโซลูชัน DIY จากชอบของ Loki หรือ Storybook (ซึ่งเป็นสิ่งที่เราใช้ก่อน Picasso) พวกเขาทั้งหมดมีข้อเสีย: บางอย่างมีราคาแพงเกินไปในขณะที่คนอื่นมีช่วงการเรียนรู้ที่สูงชันหรือต้องการการบำรุงรักษามากเกินไป

Happo ช่วยชีวิต! เป็นคู่แข่งโดยตรงกับ Percy แต่ราคาถูกกว่ามาก รองรับเบราว์เซอร์มากกว่า และใช้งานง่ายกว่า อีกจุดขายใหญ่? รองรับการรวม Cypress ซึ่งสำคัญเพราะเราต้องการเลิกใช้ Storybook สำหรับการทดสอบด้วยภาพ เราพบว่าตัวเองอยู่ในสถานการณ์ที่เราต้องสร้างเรื่องราวเพียงเพื่อให้มั่นใจว่าครอบคลุมการทดสอบด้วยภาพ ไม่ใช่เพราะเราจำเป็นต้องจัดทำเอกสารกรณีการใช้งานนั้น นั่นทำให้เอกสารของเราเสียและทำให้เข้าใจยากขึ้น เราต้องการแยกการทดสอบด้วยภาพออกจากเอกสารประกอบภาพ

การทดสอบบูรณาการ

แม้ว่าส่วนประกอบทั้งสองจะมีการทดสอบหน่วยและการมองเห็น แต่ก็ไม่รับประกันว่าจะทำงานร่วมกันได้ ตัวอย่างเช่น เราพบข้อบกพร่องที่คำแนะนำเครื่องมือไม่เปิดขึ้นเมื่อใช้ในรายการดรอปดาวน์ แต่ใช้งานได้ดีเมื่อใช้ด้วยตัวเอง

เพื่อให้แน่ใจว่าส่วนประกอบทำงานร่วมกันได้ดี เราใช้คุณสมบัติการทดสอบส่วนประกอบทดลองของ Cypress ในตอนแรก เราไม่พอใจกับประสิทธิภาพที่ไม่ดี แต่เราสามารถปรับปรุงได้ด้วยการกำหนดค่า webpack แบบกำหนดเอง ผลลัพธ์? เราสามารถใช้ API ที่ยอดเยี่ยมของ Cypress ในการเขียนการทดสอบประสิทธิภาพเพื่อให้แน่ใจว่าส่วนประกอบของเราทำงานร่วมกันได้ดี

การใช้พีระมิดทดสอบ

ทั้งหมดนี้มีลักษณะอย่างไรในชีวิตจริง? มาทดสอบส่วนประกอบหีบเพลงกัน!

สัญชาตญาณแรกของคุณอาจเป็นการเปิดโปรแกรมแก้ไขและเริ่มเขียนโค้ด คำแนะนำของฉัน? ใช้เวลาทำความเข้าใจคุณลักษณะทั้งหมดของส่วนประกอบและเขียนกรณีทดสอบที่คุณต้องการครอบคลุม

การสาธิตไลบรารีคอมโพเนนต์ของ Picasso GIF

สิ่งที่ต้องทดสอบ?

ต่อไปนี้คือรายละเอียดของกรณีที่การทดสอบของเราควรครอบคลุม:

  • สถานะ – หีบเพลง สามารถขยายและยุบได้ สถานะเริ่มต้นสามารถกำหนดค่าได้ และคุณลักษณะนี้สามารถปิดใช้งานได้
  • สไตล์ – หีบเพลงสามารถมีรูปแบบเส้นขอบได้
  • เนื้อหา – สามารถรวมเข้ากับหน่วยอื่นๆ ของห้องสมุดได้
  • การ ปรับแต่ง – ส่วนประกอบสามารถแทนที่สไตล์และสามารถมีไอคอนขยายแบบกำหนดเองได้
  • การ โทรกลับ – ทุกครั้งที่สถานะเปลี่ยนแปลง สามารถเรียกกลับได้

GIF ตัวอย่างไลบรารีคอมโพเนนต์ Picasso - ส่วนประกอบหีบเพลง

วิธีการทดสอบ?

ตอนนี้เรารู้แล้วว่าเราต้องทดสอบอะไร มาพิจารณากันว่าจะทำอย่างไร เรามีสามตัวเลือกจากปิรามิดการทดสอบของเรา เราต้องการบรรลุความครอบคลุมสูงสุดโดยมีการทับซ้อนกันน้อยที่สุดระหว่างส่วนต่างๆ ของปิรามิด วิธีใดดีที่สุดในการทดสอบกรณีทดสอบแต่ละกรณี

  • รัฐ – การทดสอบหน่วยสามารถช่วยเราประเมินว่าสถานะเปลี่ยนไปตามนั้นหรือไม่ แต่เรายังต้องการการทดสอบด้วยภาพเพื่อให้แน่ใจว่าองค์ประกอบนั้นแสดงผลอย่างถูกต้องในแต่ละสถานะ
  • สไตล์ – การทดสอบด้วยภาพน่าจะเพียงพอในการตรวจจับการถดถอยของตัวแปรต่างๆ
  • เนื้อหา – การผสมผสานระหว่างการทดสอบด้วยภาพและการผสานรวมเป็นทางเลือกที่ดีที่สุด เนื่องจากสามารถใช้ Accordions ร่วมกับส่วนประกอบอื่นๆ ได้มากมาย
  • การ ปรับแต่ง – เราสามารถใช้การทดสอบหน่วยเพื่อตรวจสอบว่าชื่อคลาสถูกนำไปใช้อย่างถูกต้องหรือไม่ แต่เราจำเป็นต้องมีการทดสอบด้วยภาพเพื่อให้แน่ใจว่าส่วนประกอบและรูปแบบที่กำหนดเองทำงานควบคู่กัน
  • การ โทรกลับ – การทดสอบหน่วยเหมาะอย่างยิ่งสำหรับการทำให้แน่ใจว่ามีการเรียกกลับที่ถูกต้อง

พีระมิดการทดสอบหีบเพลง

การทดสอบหน่วย

สามารถดูชุดการทดสอบหน่วยทั้งหมดได้ที่นี่ เราได้ครอบคลุมการเปลี่ยนแปลงสถานะ การปรับแต่ง และการโทรกลับทั้งหมด:

 it('toggles', async () => { const handleChange = jest.fn() const { getByText, getByTestId } = renderAccordion({ onChange: handleChange, expandIcon: <span data-test /> }) fireEvent.click(getByTestId('accordion-summary')) await waitFor(() => expect(getByText(DETAILS_TEXT)).toBeVisible()) fireEvent.click(getByTestId('trigger')) await waitFor(() => expect(getByText(DETAILS_TEXT)).not.toBeVisible()) fireEvent.click(getByText(SUMMARY_TEXT)) await waitFor(() => expect(getByText(DETAILS_TEXT)).toBeVisible()) expect(handleChange).toHaveBeenCalledTimes(3) })

การทดสอบการถดถอยของภาพ

การทดสอบด้วยภาพอยู่ในบล็อกอธิบาย Cypress นี้ ภาพหน้าจอสามารถพบได้ในแดชบอร์ดของ Happo

คุณสามารถดูสถานะส่วนประกอบ ตัวแปร และการปรับแต่งต่างๆ ทั้งหมดได้บันทึกไว้แล้ว ทุกครั้งที่มีการเปิด PR CI จะเปรียบเทียบภาพหน้าจอที่ Happo เก็บไว้กับภาพที่ถ่ายในสาขาของคุณ:

 it('renders', () => { mount( <TestingPicasso> <TestAccordion /> </TestingPicasso> ) cy.get('body').happoScreenshot() }) it('renders disabled', () => { mount( <TestingPicasso> <TestAccordion disabled /> <TestAccordion expandIcon={<Check16 />} /> </TestingPicasso> ) cy.get('body').happoScreenshot() }) it('renders border variants', () => { mount( <TestingPicasso> <TestAccordion borders='none' /> <TestAccordion borders='middle' /> <TestAccordion borders='all' /> </TestingPicasso> ) cy.get('body').happoScreenshot() })

การทดสอบบูรณาการ

เราเขียนการทดสอบ "เส้นทางที่ไม่ดี" ใน Cypress นี้อธิบายบล็อกที่ยืนยันว่า Accordion ยังคงทำงานได้อย่างถูกต้องและผู้ใช้สามารถโต้ตอบกับส่วนประกอบที่กำหนดเองได้ นอกจากนี้เรายังเพิ่มการยืนยันด้วยภาพเพื่อเพิ่มความมั่นใจ:

 describe('Accordion with custom summary', () => { it('closes and opens', () => { mount(<AccordionCustomSummary />) toggleAccordion() getAccordionContent().should('not.be.visible') cy.get('[data-testid=accordion-custom-summary]').happoScreenshot() toggleAccordion() getAccordionContent().should('be.visible') cy.get('[data-testid=accordion-custom-summary]').happoScreenshot() }) // … })

บูรณาการอย่างต่อเนื่อง

Picasso อาศัย GitHub Actions สำหรับ QA เกือบทั้งหมด นอกจากนี้ เราได้เพิ่ม Git hook สำหรับการตรวจสอบคุณภาพโค้ดของไฟล์ที่จัดฉาก เราเพิ่งย้ายจากเจนกินส์ไปยัง GHA ดังนั้นการตั้งค่าของเรายังอยู่ในขั้น MVP

เวิร์กโฟลว์จะทำงานบนการเปลี่ยนแปลงทุกอย่างในสาขาระยะไกลตามลำดับ โดยการรวมและการทดสอบด้วยภาพเป็นขั้นตอนสุดท้าย เนื่องจากมีค่าใช้จ่ายสูงที่สุดในการรัน (ทั้งในแง่ของประสิทธิภาพและต้นทุนทางการเงิน) เว้นแต่การทดสอบทั้งหมดจะเสร็จสมบูรณ์ ไม่สามารถรวมคำขอดึง

นี่คือขั้นตอนที่ GitHub Actions ต้องผ่านทุกครั้ง:

  1. การติดตั้งการพึ่งพา
  2. การควบคุมเวอร์ชัน – ตรวจสอบว่ารูปแบบของคอมมิตและชื่อ PR ตรงกับคอมมิตทั่วไปหรือไม่
  3. Lint – ESlint รับรองรหัสคุณภาพดี
  4. การรวบรวม TypeScript – ตรวจสอบว่าไม่มีข้อผิดพลาดประเภท
  5. การคอมไพล์แพ็คเกจ – หากไม่สามารถสร้างแพ็คเกจได้ จะไม่สามารถปล่อยแพ็คเกจได้สำเร็จ การทดสอบ Cypress ของเราคาดหวังโค้ดที่คอมไพล์แล้ว
  6. การทดสอบหน่วย
  7. บูรณาการและการทดสอบภาพ

สามารถดูเวิร์กโฟลว์แบบเต็มได้ที่นี่ ปัจจุบันใช้เวลาน้อยกว่า 12 นาทีในการดำเนินการทุกขั้นตอน

ความสามารถในการทดสอบ

เช่นเดียวกับไลบรารีส่วนประกอบส่วนใหญ่ Picasso มีองค์ประกอบรูทที่ต้องรวมองค์ประกอบอื่นๆ ทั้งหมด และสามารถใช้เพื่อตั้งกฎส่วนกลางได้ ทำให้เขียนการทดสอบได้ยากขึ้นด้วยเหตุผลสองประการ—ความไม่สอดคล้องกันในผลการทดสอบ ขึ้นอยู่กับอุปกรณ์ประกอบฉากที่ใช้ในเสื้อคลุม และต้นแบบเพิ่มเติม:

 import { render } from '@testing-library/react' describe('Form', () => { it('renders', () => { const { container } = render( <Picasso loadFavicon={false} environment='test'> <Form /> </Picasso> ) expect(container).toMatchSnapshot() }) })

เราแก้ไขปัญหาแรกด้วยการสร้าง TestingPicasso ซึ่งกำหนดเงื่อนไขล่วงหน้าสำหรับกฎสากลสำหรับการทดสอบ แต่มันน่ารำคาญที่ต้องประกาศให้ทุกกรณีทดสอบ นั่นเป็นเหตุผลที่เราสร้างฟังก์ชันการแสดงผลแบบกำหนดเองที่รวมองค์ประกอบที่ส่งผ่านใน TestingPicasso และส่งคืนทุกอย่างที่มีจากฟังก์ชันการแสดงผลของ RTL

การทดสอบของเราตอนนี้อ่านง่ายและเขียนง่ายขึ้น:

 import { render } from '@toptal/picasso/test-utils' describe('Form', () => { it('renders', () => { const { container } = render(<Form />) expect(container).toMatchSnapshot() }) })

บทสรุป

การตั้งค่าที่อธิบายไว้ที่นี่ยังห่างไกลจากความสมบูรณ์แบบ แต่เป็นจุดเริ่มต้นที่ดีสำหรับผู้ที่ชอบผจญภัยมากพอที่จะสร้างไลบรารีส่วนประกอบ ฉันได้อ่านเกี่ยวกับการทดสอบปิรามิดมามากแล้ว แต่ในทางปฏิบัติไม่ใช่เรื่องง่ายเสมอไป ดังนั้น ฉันขอเชิญคุณสำรวจ codebase ของเรา และเรียนรู้จากความผิดพลาดและความสำเร็จของเรา

ไลบรารีคอมโพเนนต์มีเอกลักษณ์เฉพาะตัวเนื่องจากให้บริการผู้ชมสองประเภท: ผู้ใช้ปลายทางที่โต้ตอบกับ UI และนักพัฒนาที่ใช้โค้ดของคุณเพื่อสร้างแอปพลิเคชันของตนเอง การลงทุนเวลาในกรอบการทดสอบที่มีประสิทธิภาพจะเป็นประโยชน์ต่อทุกคน การลงทุนเวลาในการปรับปรุงความสามารถในการทดสอบจะเป็นประโยชน์ต่อคุณในฐานะผู้ดูแลและวิศวกรที่ใช้ (และทดสอบ) ห้องสมุดของคุณ

เราไม่ได้พูดถึงเรื่องต่างๆ เช่น การครอบคลุมโค้ด การทดสอบแบบ end-to-end และนโยบายเวอร์ชันและการเผยแพร่ คำแนะนำสั้นๆ ในหัวข้อเหล่านี้คือ: เผยแพร่บ่อยๆ ฝึกฝนการกำหนดเวอร์ชันเชิงความหมายที่เหมาะสม มีความโปร่งใสในกระบวนการของคุณ และตั้งความคาดหวังสำหรับวิศวกรที่ต้องพึ่งพาไลบรารีของคุณ เราอาจทบทวนหัวข้อเหล่านี้ในรายละเอียดเพิ่มเติมในโพสต์ต่อๆ ไป