[React] React-Testing-Library λ₯Ό μ΄μ©ν TDD
νμ¬μμ TDD μ€ν°λκ° μ΄λ €μ, νλ‘ νΈμλ TDD μ ν¬λΈ μμ, λΈλ‘κ·Έ λ±μ 곡λΆλ₯Ό νκ³ μ§μ ν λ² TDD λ₯Ό ν΄λ΄€λ€. μμκ³Ό λΈλ‘κ·Έ λ±μ ν΅ν΄ μκ²λ TDD μ μ₯λ¨μ μ λ€μκ³Ό κ°λ€.
TDD μ₯μ
-
νΌλλ°± 루ν ν μ€νΈ κ²°κ³Όλ§ λ³΄λ©΄ λΈλΌμ°μ μ§μ νμΈν μΌμ΄ μ μ΄μ§λ€.
-
κ΄μ¬μ¬ κΈ°λ° κ°λ°μ΄ κ°λ₯ν΄ μ§λ€. 1). κ΄μ¬μ¬ λΆλ₯λ₯Ό μ νλ©΄ μ±μ΄ μμμ§λ€. 2). μλ‘ μνμ λν κ΄μ¬μ λΆμ°μμΌμΌ νλ€.
-
μμ‘΄μ±μ΄ μ μ΄μ§λ€. μꡬμ¬νμ λͺ ννκ² ν μ μλ€. λ λμ μ λ΄κ° μλ‘ μΆκ°ν κΈ°λ₯μ΄ λ€λ₯Έ κΈ°λ₯μλ λ λͺ¨λ₯΄κ² μν₯μ μ€ μ μλλ°, TDD λ₯Ό νλ©΄ κ·Έκ²μ λ§μμ€ μ μλ€.
-
μ€λ² μμ§λμ΄λ§μ λ§μμ€ μ μλ€.
-
λ¬Έμ μν μ νλ€.
TDD λ¨μ
- μ½λ μμ° μκ°μ΄ κΈΈμ΄μ§λ€. (λ΄κ° λͺ¨λ₯΄λ TDD λ¨μ μ΄ μμ μ μλ€.)
μ₯λ¨μ μ 곡λΆνλ©΄μ λλ κ²μ, λͺ¨λ μν©μμ TDDκ° μ λ΅μ μλλΌλ κ²μ΄λ€. λ΄κ° μκ°νμ λ λμ ν λ κ³ λ €ν΄μΌ ν μ€μν κΈ°μ€μ νμ¬μ λΉμ¦λμ€ μν©μΈ κ² κ°λ€.
π‘π‘π‘π©π»βπ»π©π»βπ»
λΉμ¦λμ€ λ¨κ³κ° νλ‘ν νμ μμ±μ΄ μ€μν λ¨κ³λΌλμ§, κ²°κ³Όλ¬Όμ 빨리 λ΄μΌ νλ μν©μ΄λΌλ©΄ TDD λμ νλ κ²μ μ€λ² μΌ μ μλ€. κ·Έλ°λ° 맀μΆμ λ΄λ μ£Όμ κΈ°λ₯λ€μ΄ μμ νλ μ±μλ¨κ³μ μλ λ¨κ³λ, κΈ°μ‘΄ μλ²κ° μκ³ μλ‘μ΄ μλ²λ‘ λ§μ΄κ·Έλ μ΄μ νλ λ¨κ³μμλ TDD λμ μ ν΅ν΄ λ‘μ§μ μ¬κ²μ¦νκ³ μ»΄ν¬λνΈλ€μ μκ² μͺΌκ°λ©΄μ κΈ°λ₯μ λͺ©μ μ λͺ νν ν μ μμ κ² κ°λ€.
TDD, μ§μ ν΄λ³΄μμ΅λλ€.
κΆκΈν΄μ TDD λ‘ μμ£Ό μμ κ°λ°μ ν΄λ³΄μλ€. μμ Canvas API μ κ΄μ¬μ΄ μ겨μ, νν 리μΌμ μμνλλ°, μ΄κ±Έ 리μ‘νΈλ‘ ꡬννλ κ²μ TDD λ‘ ν΄λ³΄μλ€.
React-Testing-Library, CRA λ λͺ»νλκ² μꡬλ
κ°λ°μ μμνκΈ° μ μ μ°μ RTL (React-Testing-Library) μ λν΄ μ’ λ μκ³ μΆμλ€. RTL μ Kent C. Dodds κ° κ°λ°ν React testing tool λ‘, airbnb μ enzyme μ λ체μ¬λ‘ μλ €μ§κ³ μλ€κ³ νλ€.
RTL vs Enzyme
So rather than dealing with instances of rendered React components, your tests will work with actual DOM nodes.
β 곡μ λ¬Έμλ DOM Testing library μμ κ°μ‘°νκ³ μλ€. React component μΈμ€ν΄μ€κ° μλλΌ, ν μ€νΈλ μ€μ λΈλΌμ°μ μ κ·Έλ €μ§ DOM nodes λ₯Ό μ΄μ©ν΄ μ΄λ£¨μ΄μ§λ€. RTL λΌμ΄λΈλ¬λ¦¬λ μ€μ μ μ μ νλκ³Ό λμΌνκ² DOM μ μ°Ύμλ€λλ©° μλλλ‘ κ·Έλ €μ‘λ μ§λ₯Ό νμΈνλ€.
Enzyme gives React developers utilities to test internals of React components, React Testing Library takes a step back and questions us "how to test React components to get full confidence in our React components": Rather than testing a component's implementation details, React Testing Library puts >the developer in the shoes of an end user of an React application.
β Enzyme μ΄ React component κ΄μ μμ μ μ€νμ΄ λμλ μ§λ₯Ό ν μ€νΈνλ ν΄μ΄λΌλ©΄, RTL μ μλμ μ μ μ₯μμ κ°λ°μμ μλλλ‘ νλ©΄μ΄ λ³΄μ΄λ μ§λ₯Ό ν μ€νΈ νλ ν΄μ΄λ€.
RTL vs Jest
λ°λ©΄μ, Jest λ RTL κ³Ό 보μκ΄κ³μ΄λ€. React λ₯Ό μ μ¨λ΄€λ€κ³ ν΄λ javascript application μμ ν μ€νΈλ₯Ό ν΄λ³Έ μ¬λλ€ μ€ λλΆλΆμ μλμ κ°μ μ½λλ₯Ό λ³Έ μ μ΄ μμ κ²μ΄λ€.
// test suite describe('true is truthy and false is falsy', () => { // test case 1 test('true is truthy', () => { expect(true).toBe(true); }); // test case 2 test('false is falsy', () => { expect(false).toBe(false); }); });
μ μ½λλ₯Ό test-suit μ΄λΌνλ€. ν μ€νΈνλ κ°μλ₯Ό describe ν΄μ£Όκ³ , ν μ€νΈν΄μ λμ€λ κΈ°λκ°μ λΉκ΅ν΄μ£Όλ μ½λλ₯Ό λ΄λλ€.
μ€μΌμ΄.. μ΄μ μ΄λμ λ RTL μμ΄λμ΄λ μ΄ν΄κ° λμλ€. κ°λ¨ν λΉ¨κ°μ μ¬κ°νμ 그리λ κ±Έλ‘ μ²« TDD λ₯Ό ν΄λ³Έλ€.
μ§μ ν΄λ³΄κΈ°
create-react-app νλ©΄ μλμΌλ‘
@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.1.0", "@testing-library/user-event": "^12.1.10",
μΈ κ°κ° μ€μΉ λμ΄ μλ€. μμ¦ μΈμ νΈνλ€ π μ΄λ―Έ create-react-app μ ν΅ν΄ λ§λ€μ΄ μ°κ³ μλ React λ ν¬κ° μμ΄μ, κ±°κΈ°μ RTL μ μ€μΉνλ €κ³ λ³΄λ μ΄λ―Έ default λ‘ κΉλ €μ Έ μμλ€.
canvas.test.js νμΌμ λ¨Όμ λ§λ λ€.
import React from 'react'; import { render } from '@testing-library/react'; import RedRectangle from './RedRectangle'; describe('RedRectangle', () => { test('renders RedRectangle', () => { render(<RedRectangle />); }) })
import React from 'react'; const RedRectangle = () => { return ( <div></div> ) }; export default RedRectangle;
λ§λ€κ³ , λ€μ ν μ€νΈ.
ν μ€νΈ ν΅κ³Όνμ¬ λ€μμ canvas μ리먼νΈλ₯Ό λ£κΈ° μ μ, canvas element κ° DOM μ κ·Έλ €μ‘λμ§ νμΈνλ ν μ€νΈ μ½λλ₯Ό μ§ λ€.
import { render, screen } from '@testing-library/react'; import RedRectangle from './RedRectangle'; describe('RedRectangle', () => { test('renders RedRectangle', () => { render(<RedRectangle />); }) test('render canvas element', () => { screen.getByTestId('canvas'); // νλ©΄μ dataset id = cavas μΈ element κ° μλμ§ νμΈν΄μ€λ€. }) })
κ²°κ³Όλ λΉμ°ν FAIL (μμ§ μ λ§λ€μ΄μ€¬μΌλκΉ)
κ·Έλμ Canvas μ»΄ν¬λνΈλ₯Ό μμ±νλ€.
import React, {useRef, useEffect } from 'react'; const Canvas = ({draw, height, width}) => { const canvas = useRef(null); useEffect(() => { const context = canvas.current.getContext('2d'); draw(context); }); return ( <canvas ref={canvas} height={height} width={width} /> ); }; export default Canvas;
κ·Έλ¦¬κ³ μ Canvas μ»΄ν¬λνΈλ₯Ό import ν΄μ
import React from 'react'; import Canvas from './Canvas'; const RedRectangle = () => { const draw = (context) => { // context.fillRect(x, y, width, height) -> x, y λ μμ μ’ν. context.fillStyle = "red"; context.fillRect(100, 100, 400, 300); } return ( <Canvas draw={draw} width={800} height={600} /> ) }; export default RedRectangle;
λΉ¨κ° μ¬κ°νμ κ·Έλ €λ΄€λλ°,
μ΄λ κ² λΈλΌμ°μ μλ μ λ λλ§ λμ§λ§, ν μ€νΈλ κΉ¨μ§λ€.
npm start λ₯Ό ν΄μ context λ₯Ό μ°μ΄λ³΄λ©΄ μλμ²λΌ μ λμ¨λ€. μ ν μ€νΈμμλ λͺ» λ°μκΉ?
μμΈμ canvas api λ λΈλΌμ°μ dom μ κ·Έλ €μ§λ κ²μΈλ°, RTL κ³Ό jest λ jsdom μ΄λΌλ κ°μ§ λ (ν μ€νΈλ₯Ό μν λΆλΆλ§ μΆλ €μ€λ) μ κ°μ§κ³ ν μ€νΈλ₯Ό νμ§, μ§μ§ λΈλΌμ°μ μλ μκ΄μ΄ μκΈ° λλ¬Έμ Canvas element λ₯Ό λͺ» μ°Ύλ κ²μ΄μλ€.
κ²μν΄λ³΄λ, canvas μλ¦¬λ¨ΌνΈ ν μ€νΈ λΌμ΄λΈλ¬λ¦¬λ‘ https://www.npmjs.com/package/jest-canvas-mock κ° μμλ€. κ·Έλ°λ° jest-canvas-mock μ λ΄ λ¦¬μ‘νΈ μ±μΈ CRA react-script 4+ λ²μ μμ μΆ©λλ¬Έμ κ° μμ΄μ, node μμ canvas λμ μ κ·Όνκ² ν΄μ£Όλ node-canvas λΌμ΄λΈλ¬λ¦¬λ₯Ό μ€μΉνλλ ν μ€νΈκ° μ±κ³΅νμλ€. π₯³
π‘π‘π‘π©π»βπ»π©π»βπ» TDD ν΄λ³Έ μκ°
μμμμ λ΄€λ κ²μ²λΌ, μ§κΈ ν΄μΌ ν μΌκ³Ό λ€μ ν΄μΌ ν μΌμ΄ λͺ νν΄μ Έμ μ’μλ€. λ€λ§ ν μ€νΈμ μ΄ canvas μ리먼νΈλ μμ§ μλ²½ν ν μ€νΈ ν΄μ΄ μ§μλμ΄ μλ κ² κ°μ§ μμλ€. κ·Έλ μ§λ§ SRP μ λ§μΆμ΄ κ°λ°νλ κ²μλ νμ€ν λμμ΄ λλ κ² κ°λ€. κ³μ μ¨λ³΄κ³ μΆλ€!
πΒ λ νΌλ°μ€ RTL
https://www.robinwieruch.de/react-testing-library/
https://testing-library.com/docs/react-testing-library/intro/#tutorials
react - canvas 그리기
https://velog.io/@mokyoungg/React-Reactμμ-Canvas-μ¬μ©νκΈ°λ§μ°μ€-그리기