HARD
PR 체ν¬ν¬μΈνΈ λ° κ΅¬ν λ΄μ©
7μ£Όμ°¨ κ³Όμ 체ν¬ν¬μΈνΈ
κΈ°λ³Έκ³Όμ
- μ΄ 11κ°μ νμΌ, 115κ°μ λ¨μ ν μ€νΈλ₯Ό μμ±νκ³ λͺ¨λ ν΅κ³Ό
μ§λ¬Έ λ΅λ³
Q1. handlersUtilsμ λ¨κΈ΄ μ§λ¬Έμ λ΅λ³ν΄μ£ΌμΈμ.
μ΄λ²€νΈλ μμ±, μμ λλ©΄ fetchλ₯Ό λ€μ ν΄ μνλ₯Ό μ λ°μ΄νΈν©λλ€. ν μ€νΈκ° λ³λ ¬λ‘ λμλ μμ μ μ΄κ² λμν μ μλ λ°©λ²μ?
μ²μμλ κ·Έλ₯ handlers.ts μμ μ μ events λ°°μ΄μ κ° ν
μ€νΈλ§λ€ μ΄κΈ°ννλ©΄ λκ² λ€κ³ μκ°νμ΅λλ€. κ·Έλ°λ° μ€νν΄λ³΄λ ν ν
μ€νΈμμ μΆκ°ν μ΄λ²€νΈκ° λ€λ₯Έ ν
μ€νΈμ λνλκ³ , μμ ν
μ€νΈλ₯Ό λλ Έλλ μλ±ν ν
μ€νΈκ° κΉ¨μ§λ λ¬Έμ κ° λ°μνμ΅λλ€.
μ΄ λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄ EventTestStore ν΄λμ€λ₯Ό λ§λ€κ³ , κ° ν
μ€νΈλ§λ€ λ
립μ μΈ μ μ₯μλ₯Ό μμ±νλλ‘ λ°κΏ¨μ΅λλ€. Map μλ£κ΅¬μ‘°λ‘ CRUDλ₯Ό ꡬννκ³ , setupMockEvents()μμ λ§€λ² μλ‘μ΄ μΈμ€ν΄μ€λ₯Ό μμ±νκ² νλ λ³λ ¬ μ€νμμλ μμ μ μΌλ‘ λμνμ΅λλ€.
Q2. ν μ€νΈλ₯Ό λ 립μ μΌλ‘ ꡬλμν€κΈ° μν΄ μμ±νλ μ€μ λ€μ μκ°ν΄μ£ΌμΈμ.
μ¬λ¬ μνμ°©μ€ λμ λ€μκ³Ό κ°μ λ°©λ²μ μ μ©νμ΅λλ€.
- ID μΆ©λ λ°©μ§: λ¨μ μ«μ IDλ μΆ©λμ΄ μ¦μ
crypto.randomUUID()μDate.now()λ₯Ό μ‘°ν©ν΄ μ¬μ© - MSW νΈλ€λ¬ 격리: κ° ν
μ€νΈμμ
server.use(...setupMockEvents([]))λ‘ μ΄κΈ° λ°μ΄ν° μ§μ - νμ΄λ¨Έ 격리: μλ¦Ό ν
μ€νΈμμ μκ° λ¬Έμ λ‘ κ³ μνλλ°, κ²°κ΅ κ° ν
μ€νΈλ₯Ό
vi.useFakeTimers()/vi.useRealTimers()λ‘ κ°μΈ ν΄κ²°
μ¬ν κ³Όμ
- App μ»΄ν¬λνΈλ₯Ό μ μ ν λΆλ¦¬ (μ»΄ν¬λνΈ, ν , μ νΈ ν¨μ)
- λΆλ¦¬λ λͺ¨λλ€μ λν΄ 5κ° μ΄μ ν μ€νΈ μμ±
μ£Όμ ꡬν λ΄μ©
1. ν μ€νΈ μμ μ± κ°μ
μ²μμ νλμ© μ€νν λλ ν΅κ³Όνμ§λ§ μ 체λ₯Ό λ리면 μ λ° μ΄μμ΄ κΉ¨μ‘μ΅λλ€. μμΈμ΄ μ μ λ°°μ΄μ΄λΌλ κ±Έ μμλ΄κΈ°κΉμ§ μκ°μ΄ κ½€ κ±Έλ Έμ΅λλ€. EventTestStoreλ₯Ό λμ
ν λ€μλ μμ λ¬Έμ λ€μ΄ μ΄μ΄μ‘μ§λ§, κ²°κ΅ ν΅μ¬μ "κ° ν
μ€νΈκ° μμ ν λ
립λ νκ²½μμ λμμΌ νλ€"λ μ μ΄μμ΅λλ€.
2. ν΅ν© ν μ€νΈ κ°μ
μ¬μ©μ μλ리μ€λλ‘ ν
μ€νΈλ₯Ό μ§λ κ² μκ°λ³΄λ€ μ½μ§ μμμ΅λλ€. μλ₯Ό λ€μ΄ "μΌμ μΆκ°"λ§ ν΄λ μ
λ ₯ β μ μ₯ λ²νΌ ν΄λ¦ β μλ² μμ² β λͺ©λ‘ μ
λ°μ΄νΈκΉμ§ λ¨κ³κ° λ§κ³ , λΉλκΈ° μ²λ¦¬ λλ¬Έμ waitFor, findByλ₯Ό μμ£Ό μΈ μλ°μ μμμ΅λλ€.
3. μ νΈλ¦¬ν° ν¨μ ν μ€νΈ κ°ν
μμ ν¨μλΌ μμ±μ λΉκ΅μ μμνμ§λ§, λ μ§ κ΄λ ¨ μ£μ§ μΌμ΄μ€(μ€λ , μλ§ λ±)λ₯Ό κ³ λ €νλ κ³Όμ μ΄ κΉλ€λ‘μ μ΅λλ€.
κ³Όμ μ ννκ³
κΈ°μ μ μ±μ₯
νλ‘ νΈμλμ λ°±μλμμμ ν μ€ν κ΄μ μ°¨μ΄
λ°±μλμμλ λλ©μΈ κ°μ²΄μ λΉμ¦λμ€ λ‘μ§μ΄ μ€μ¬μ λλ€.
- ν¨μ λ¨μ, λ‘μ§ λ¨μμμ λ°μν μ μλ μ¬μ΄λ μ΄ννΈ μ΅μνμ μ§μ€νμ΅λλ€.
μ λ ν μ€νΈλ μ λ ₯κ³Ό μΆλ ₯λ§ λͺ νν μ μνλ©΄ λμκ³ , 리ν©ν°λ§ μ μμ λ§ μν μ μΆ©μ€ν νμ΅λλ€.- μλ₯Ό λ€μ΄, OASλ‘ API μ€νμ μ μν λ€, μ λ ₯/μΆλ ₯ κ°μ΄ λ°λμ§ μλ ν ν μ€νΈ μ½λλ μμ μ μΌλ‘ μ μ§λμμ΅λλ€.
λ°λ©΄ νλ‘ νΈμλμμλ ν¨μ¬ λ€λ₯Έ μ±κ²©μ μ΄λ €μμ΄ μμμ΅λλ€.
- ν΄λ¦ β μν λ³ν β μλ² μμ² β UI μ λ°μ΄νΈλΌλ μ¬μ©μ νλ‘μ° μ 체λ₯Ό κ²μ¦ν΄μΌ νμ΅λλ€.
- νΉν λΉλκΈ° ν΅μ , DOM μ λ°μ΄νΈ νμ΄λ°, νμ΄λ¨Έμ κ°μ UI νΉμμ±μ΄ κ²°ν©λλ©΄μ, λ¨μν ν¨μ 리ν΄κ°λ§ 보λ λ°±μλ ν μ€νΈλ³΄λ€ ν¨μ¬ 볡μ‘νμ΅λλ€.
- λ°λΌμ λ¨μ μ λ ν
μ€νΈλ³΄λ€λ ν΅ν© ν
μ€νΈ μλλ¦¬μ€ μ€κ³μ ν
μ€νΈ κ²©λ¦¬κ° ν΅μ¬μ΄ λμκ³ , μ΄λ² κ³Όμ μμλ
EventTestStoreκ°μ λ³λμ ꡬ쑰λ₯Ό μ€κ³ν΄μΌλ§ λ³λ ¬ μ€ν νκ²½μμλ μμ μ±μ ν보ν μ μμμ΅λλ€.
μ¦,
- λ°±μλλ λ‘μ§ κ²μ¦μ΄ μ£Όκ° λμλ€λ©΄,
- νλ‘ νΈμλλ μ¬μ©μ κ²½ν(UX) μλλ¦¬μ€ λ³΄μ₯μ΄ ν μ€νΈμ λ³Έμ§μ λͺ©νμμ΅λλ€.
κ³Όκ±° λΈλ‘κ·Έ κ²½νκ³Όμ μ°κ²°
κ³Όκ±°μ λΈλ‘κ·Έ ν¬μ€ν μμ,
βμ λ ν μ€νΈκ° μμΌλ©΄ 리ν©ν°λ§μ΄ λλ ΅μ§ μμλ€β
λΌλ κ²½νμ μ΄ μ μ΄ μμ΅λλ€. κ·Έλλ 리ν©ν°λ§μ νλ©° λλ μ μ΄μλλ°, μ΄λ² κ³Όμ λ₯Ό νλ©° λκ°μ κΉ¨λ¬μμ λ€μ νμ΅λλ€.
νλ‘ νΈμλμμλ ν μ€νΈκ° μμΌλ μ»΄ν¬λνΈλ₯Ό λΆλ¦¬νκ³ , ν μΌλ‘ λ‘μ§μ μΆμΆνκ³ , ꡬ쑰λ₯Ό κ³Όκ°ν λ°κΎΈλ κ³Όμ μ΄ λλ ΅μ§ μμμ΅λλ€. μ΄λ² κ²½νμ βν μ€νΈλ λ°±μλ/νλ‘ νΈμλλ₯Ό κ°λ¦¬μ§ μκ³ κ°λ°μμ μμ κ°μ λμ¬μ£Όλ κ°μ₯ κ°λ ₯ν λꡬβλΌλ κ±Έ λ€μ νλ² νμΈν μκ°μ΄μμ΅λλ€.
νμ΄λ¨Έ κ΄λ ¨ ν μ€νΈ μ΄μ
fake timerλ₯Ό μ°λ©΄μ μκ°μ΄ μ§λλ μλ¦Όμ΄ λ¨μ§ μλ λ¬Έμ κ° μμμ΅λλ€. μμΈμ fake timerλ μκ°μ κ°μ§λ‘ μ§νμν€λ λ°λ©΄, Reactμ μν μ
λ°μ΄νΈλ waitForλ μ€μ μκ°μ μ°Έμ‘°νλ€λ μ μ΄μμ΅λλ€.
(νλ μλμ μμλκ» μ΄κ±° λλ? μ¬μ€λ³΄λ λλΈ μλμ λ§ν¬λ₯Ό 보λ΄μ£ΌλλΌκ³ μ. νμ κ³ λ§μ΄ μμλ γ γ )
- fake timerλ κ°μ§λ‘ μκ°μ μ§νμν€λλ°
- Reactμ μν μ λ°μ΄νΈλ waitForλ μ€μ μκ°μ μ°λλΌκ΅¬μ
- κ·Έλμ λμ΄ μ±ν¬κ° μ λ§μμ ν μ€νΈκ° μ λλ‘ μ λμκ°
ν΄κ²° λ°©λ²μ λ€μκ³Ό κ°μμ΅λλ€.
vi.useFakeTimers({ shouldAdvanceTime: true });
await act(async () => {
vi.advanceTimersByTime(1000);
});
shouldAdvanceTime μ΅μ
μ μκ² λ νμμμΌ λ¬Έμ λ₯Ό ν΄κ²°ν μ μμμ΅λλ€. λ¬Έμμμ μ°ΎκΈ° νλ€μ΄ μ λ₯Ό λ§μ΄ λ¨Ήμλ λΆλΆμ
λλ€.
μ½λ νμ§
- λ§μ‘±μ€λ¬μ΄ λΆλΆ:
EventTestStoreμ€κ³. λ¨μν Mapλ§μΌλ‘λ 볡μ‘ν λ¬Έμ λ₯Ό κΉλνκ² μ 리ν μ μμμ΅λλ€. - μμ¬μ΄ λΆλΆ: ν΅ν© ν μ€νΈκ° κΈΈμ΄μ Έ κ°λ μ±μ΄ λ¨μ΄μ§ μ . κ³΅ν΅ λμμ ν¬νΌ ν¨μλ‘ μΆμΆνλ λ± κ°μ μ¬μ§κ° μμ΅λλ€.
νμ΅ ν¨κ³Ό
ν μ€νΈκ° 리ν©ν°λ§ κ³Όμ μμ μΌλ§λ ν° νμ΄ λλμ§ μ²΄κ°νμ΅λλ€. ꡬ쑰λ₯Ό κ³Όκ°νκ² λ°κΏ μ μμλ 건, ν μ€νΈκ° κΈ°λ₯μ΄ μ μ§λκ³ μμμ 보μ₯ν΄μ€¬κΈ° λλ¬Έμ λλ€.
μμ§μ μκ°μ ν μ€νΈλ μ€λ μ· ν μ€νΈ νμ© μμ μ΄ μ λ§€νκ² λκ»΄μ§λλ€. μ΄ λΆλΆμ λ νμ΅μ΄ νμν κ² κ°μ΅λλ€.
κ³Όμ νΌλλ°±
- μ’μλ μ : μ€λ¬΄μ κ°κΉμ΄ μ±μ λμμΌλ‘ ν μ€νΈλ₯Ό μ°μ΅ν μ μμκ³ , MSWλ μ λλ‘ νμ©ν΄λ³Ό κΈ°νμμ΅λλ€.
- μμ¬μ΄ μ : λ³λ ¬ μ€ν νκ²½μμ ν μ€νΈλ₯Ό μμ μ μΌλ‘ λ리λ λ°©λ²μ λν κ°μ΄λκ° μ‘°κΈλ§ λ μμμΌλ©΄ μνμ°©μ€λ₯Ό μ€μΌ μ μμμ κ² κ°μ΅λλ€.
리뷰 λ°κ³ μΆμ λ΄μ©
-
EventTestStore ν¨ν΄ Map κΈ°λ°μΌλ‘ ꡬννλλ°, μ΄ λ°©μμ΄ λ€λ₯Έ νλ‘μ νΈμμλ μΌλ°μ μΌλ‘ μ¬μ©νλ μ κ·ΌμΈμ§ κΆκΈν©λλ€. factory ν¨ν΄μ΄λ builder ν¨ν΄μΌλ‘ νμ₯νλ κ² λ μ μ ν κΉμ?
-
ν΅ν© ν μ€νΈ λ²μ
medium.integration.spec.tsxκ°μ κ²½μ°, "μΌμ μΆκ°" ν μ€νΈμμ νΌ μ λ ₯ β μ μ₯ β λͺ©λ‘ νμΈκΉμ§ μ κ³Όμ μ ν ν μ€νΈλ‘ λμλλ°μ. μ΄λ κ² κΈ΄ μλ리μ€λ₯Ό κ·Έλλ‘ λλ κ² λ§λμ§, μλλ©΄ μͺΌκ°λ κ² λ λ°λμ§νμ§ κ³ λ―Όμ λλ€. λ§μ½ μͺΌκ° λ€λ©΄ μ΄λ€ κΈ°μ€μ΄ μ μ ν κΉμ? -
ν μ€νΈ λ°μ΄ν° κ΄λ¦¬
createTestEvent()λ₯Ό ν΅ν΄ κΈ°λ³Έκ°μ μΈν νκ³ νμν λΆλΆλ§ μ€λ²λΌμ΄λνλ λ°©μμ μΌμ΅λλ€. κ·Έλ°λ° κ²½μ°μ λ°λΌμ μ€νλ € νΌλμ€λ½κΈ°λ νμ΅λλ€. λ§€λ² μμ ν λ°μ΄ν°λ₯Ό μλ‘ λ§λλ λ°©μκ³Ό λΉκ΅νμ λ μ΄λ€ μ κ·Όμ΄ λ μ μ§λ³΄μμ μ 리ν κΉμ?
κ³Όμ νΌλλ°±
μλ νμΈμ μ€νλ! 7μ£Όμ°¨ κ³Όμ μ μ§νν΄μ£Όμ ¨λ€μ γ γ
μ€νλκ»μ μμ±ν΄μ£Όμ ν μ€νΈμ λν κ΄μ μ΄ λ¬΄μ² μΈμμ μ΄μμ΄μ. μ λ μ΄λ° μκ°μ ν΄λ³Έμ μ΄ λ±ν μμλλ°, λλΆμ μ’μ μΈμ¬μ΄νΈ μ»μ΄κ°λλ€!
νλ‘ νΈλ κ²°κ΅ dataμ ννμ μ§μ€μ΄ λμ΄μλ κ²½μ°κ° λ§λ€λ³΄λ.. ν μ€νΈμ ν¨κ³Όλ₯Ό 체κ°νκΈ° μ΄λ €μ΄ λΆλΆμ΄ λΆλͺ μμΌλ¦¬λΌ μκ°ν΄μ. λ€λ§ μ΄κ²λ μ΄λ€ μλΉμ€ νΉμ λꡬλ₯Ό λ§λλμ λ°λΌ λ¬λΌμ§ μ μμ΄μ ν μ€νΈ μμλ "λΉμ¦λμ€"μ λν λ΄μ©μ΄ μΆκ°λμ΄μΌ νλ€κ³ μκ°νλ΅λλ€ γ γ
μ κ° λ§λλ μ νμ κ²½μ° uxλ³΄λ¨ μ§μ§λ‘ λ°±μλμ²λΌ λ°μ΄ν°μ λν input/output μ΄ λ¬΄μ² μ€μνλ€λ³΄λ..
EventTestStore ν¨ν΄: Map κΈ°λ°μΌλ‘ ꡬννλλ°, μ΄ λ°©μμ΄ λ€λ₯Έ νλ‘μ νΈμμλ μΌλ°μ μΌλ‘ μ¬μ©νλ μ κ·ΌμΈμ§ κΆκΈν©λλ€. factory ν¨ν΄μ΄λ builder ν¨ν΄μΌλ‘ νμ₯νλ κ² λ μ μ ν κΉμ?
μΌλ°μ μΈ μ κ·Όμ μλλΌκ³ λκΌμ΄μ. μ΄κ² νμν μ΄μ κ° κ° ν μ€νΈκ° λ€λ£¨λ λ°μ΄ν°λ₯Ό λ 립μ μΌλ‘ λ€λ£¨κΈ° μν¨μΈλ° λ³΄ν΅ beforeEach, beforeAll, afterEach, afterAll λ±μμ μ΄κΈ°νλ₯Ό ν΄μ£Όκ³ , μ΄κΈ°νκ³Ό μλ£λ μμ μ ν μ€νΈλ₯Ό μ§ννλ€κ±°λ νλκΉμ γ γ
μ€νλκ»μ λ§λ€μ΄μ£Όμ 건 λ°μ΄ν°λ₯Ό μ΄κΈ°ννλ€κΈ°λ³΄λ¨ λ°μ΄ν°λ₯Ό μμ λ 립μ μΌλ‘ λΆλ¦¬ν΄μ κ΄λ¦¬νλ©΄ μ’μ§ μμκΉ!? λΌλ μλλ‘ λ³΄μμ΅λλ€. μ’μ μμ΄λμ΄λΌκ³ μκ°ν΄μ!
κ·Έλ¦¬κ³ μ΄κ±Έ λ§λ€μ΄κ°λ λ°©μμ.. builderλ μ λͺ¨λ₯΄κ² κ³ factory (createData κ°μ...?) λ°©μμΌλ‘ λ§λ€λ©΄ λμμ§ μμ κ² κ°λ€μ!
μ μκ°ν΄λ³΄λ, μ ν¬ νμ create~~~ λ°©μμΌλ‘ ν μ€νΈ λ°μ΄ν°λ₯Ό κ° ν μ€νΈλ§λ€ λ§λ€μ΄μ μ¬μ©νκ³ μλ€μ γ γ
ν΅ν© ν μ€νΈ λ²μ: medium.integration.spec.tsx κ°μ κ²½μ°, "μΌμ μΆκ°" ν μ€νΈμμ νΌ μ λ ₯ β μ μ₯ β λͺ©λ‘ νμΈκΉμ§ μ κ³Όμ μ ν ν μ€νΈλ‘ λμλλ°μ. μ΄λ κ² κΈ΄ μλ리μ€λ₯Ό κ·Έλλ‘ λλ κ² λ§λμ§, μλλ©΄ μͺΌκ°λ κ² λ λ°λμ§νμ§ κ³ λ―Όμ λλ€. λ§μ½ μͺΌκ° λ€λ©΄ μ΄λ€ κΈ°μ€μ΄ μ μ ν κΉμ?
λ¬Έμ λ₯Ό μ λ°κ²¬ν μ μλ€λ©΄ μ΄λ€ λ°©μμ΄λ μ€μν κΉ? λΌκ³ μκ°ν΄μ. λ¬Όλ‘ ν μ€νΈλ₯Ό λ μ μμ±νκ³ κ΄λ¦¬ν μ μλ λ°©λ²μ΄ μκ² μ§λ§ μ€μν건 ν μ€νΈλ₯Ό ν΅ν΄ μ¬μ΄λ μ΄ννΈλ₯Ό μ°Ύμμ μ‘°κΈ°μ‘°μΉ ν μ μλκ² ν μ€νΈμ 첫 λ²μ§Έ μμΉμ΄λΌκ³ μ€μ€λ‘ μκ°νκ³ μμ΄μ.
κ·Έλμ λ§μν΄μ£Όμ κ² μ²λΌ ν΄λ 무방νκ³ , μ΄κ±Έ μͺΌκ° λ€λ©΄ μλ§ κ·Έλ₯ μΌλΆ κ³Όμ μ μ νΈ ν¨μ κ°μκ±Έλ‘ λΆλ¦¬ν΄μ λ€λ£° μ μμ§ μμκΉ!? λΌλ μκ°μ΄ λ€μ΄μ γ γ
μ΄λ° λλμ΄μ£ .
test('μΌμ μΆκ° ν
μ€νΈ', () => {
νΌμ
λ ₯_κ²μ¦();
νΌμ μ₯_κ²μ¦();
λͺ©λ‘νμΈ_κ²μ¦();
})
κ·Όλ°.. λ±ν μ λ΅μ μλ€κ³ μκ°ν΄μ γ γ
ν μ€νΈ λ°μ΄ν° κ΄λ¦¬: createTestEvent()λ₯Ό ν΅ν΄ κΈ°λ³Έκ°μ μΈν νκ³ νμν λΆλΆλ§ μ€λ²λΌμ΄λνλ λ°©μμ μΌμ΅λλ€. κ·Έλ°λ° κ²½μ°μ λ°λΌμ μ€νλ € νΌλμ€λ½κΈ°λ νμ΅λλ€. λ§€λ² μμ ν λ°μ΄ν°λ₯Ό μλ‘ λ§λλ λ°©μκ³Ό λΉκ΅νμ λ μ΄λ€ μ κ·Όμ΄ λ μ μ§λ³΄μμ μ 리ν κΉμ?
μ΄λ€ λΆλΆμ΄ νΌλμ€λ½κ² λκ»΄μ‘μκΉμ!? μ μ§λ³΄μμ μ’μ λ°©μμ΄ λκΉ κ³ λ―Όν΄λ³΄μλ©΄, ν μ€νΈλ₯Ό λ³΄κ³ μ΄λ€ κ°μ΄ ννλκ³ μλμ§ μ΄λ€ κ°μ μμ νλμ§ ν λμ λ³Ό μ μμΌλ©΄ μ’λ€κ³ μκ°ν΄μ. μ¬νμ©μ μΈ‘λ©΄λ³΄λ€ μ½κΈ°κ° μμνκ°? μ λν μΈ‘λ©΄μ΄ ν μ€νΈμμλ λ μ€μνλ€κ³ μκ°ν©λλ€!
κ·Έλμ μ§κΈ λ°©μλ λμμ§ μλ€κ³ μκ°ν΄μ γ γ