π§ Test Doubleμ΄λ?
ν μ€νΈ λλΈμ΄λ μ€μ ꡬνμ²΄λ‘ ν μ€νΈλ₯Ό μ§ννκΈ° μ΄λ €μ΄ κ²½μ°, μ΄λ₯Ό λμ ν΄μ ν μ€νΈλ₯Ό μ§νν μ μλλ‘ λ§λ€μ΄μ§λ κ°μ²΄μ΄λ€.
Test Double μ΄λ λͺ μΉμ μ λ π
μνλ₯Ό 촬μνλ κ²½μ°, μνν μ₯λ©΄ 촬μν λ μ€μ λ°°μ°λ₯Ό λμ ν΄μ 촬μνλ μ€ν΄νΈ λλΈμμ μ λλ λ¨μ΄μ΄λ€.
μ¬μ© μ΄μ π
μ΄μ μ 'ν μ€νΈ μ£Όλκ°λ° μμνκΈ°' λΌλ μ± μ μ½μ μ μ΄ μλλ°, ν΄λΉ μ± μ μμ λ§μ λΉλ¦¬μλ©΄
ν μ€νΈ λλΈμ μΈλΆ μμΈμ μμ‘΄νλ κ°μ²΄μ λν ν μ€νΈλ₯Ό μμ±ν λ "μ€ν¨νλ ν μ€νΈλ νμ μ€ν¨νκ³ , μ±κ³΅νλ ν μ€νΈλ νμ μ±κ³΅νλ€" λΌλ ν μ€νΈμ μΌκ΄μ±μ μ§ν€κΈ° μν΄ μ¬μ©νλ€κ³ νλ€.
μλ₯Ό λ€μ΄ DB, μΈλΆ API λ±μ μ¬μ©ν λ, λ€νΈμν¬ μ°κ²° μν λ±μ ν¬ν¨ν λ€μν λ³μΉμ μ΄μ μ μν΄μ ν μ€νΈκ° μ€ν¨νλ μν©μ΄ λ°μν μ μμ κ²μ΄λ€.
μ΄λ¬ν λ¬Έμ μ λν΄ μ€μ ꡬν체μ λμμΈ ν μ€νΈ λλΈμ μ¬μ©νμ¬ ν μ€νΈκ° μ΄λ€ μν©μ΄λ κ°μ λμν μ μλλ‘ λ§λ€μ΄μ£Όλ κ²μ΄λ€.
'μΈλΆ μμΈ' μ λ²μ
μ½λ 리뷰λ₯Ό μ£Όκ³ λ°μΌλ©° νμ μμΈ λ¦¬λ·°μ΄λ ν μ€νΈ λλΈλ‘ μ²λ¦¬ν΄μΌνλ μΈλΆ μμΈμ λ²μλ₯Ό μ§μ νλ κ²μ΄ κ°μ₯ μ€μνλ€κ³ μκΈ°ν΄μ£Όμ ¨λ€.
μ΄μ λν΄μ λ³ΈμΈμ κΈ°μ€μ ν μ€ μ μ΄λ³΄μλ©΄
API μλ² κ°λ°μ μ¬μ©νλ μ€νλ§λΆνΈ μ ν리μΌμ΄μ μ΄ μλ λͺ¨λ μΈλΆ μμ‘΄μ±λ€μ μΈλΆ μμΈμ΄λΌκ³ λ μκ°νμ§λ μλλ€.
μλ₯Ό λ€μ΄ H2 DBλ₯Ό In-Memory & Embedded λͺ¨λλ‘ μ¬μ©νλ€λ©΄, μ΄λ μ€νλ§λΆνΈ μ ν리μΌμ΄μ λ΄λΆμμ μλνλ©° λ€νΈμν¬κ° μμ΄λ μ ν리μΌμ΄μ λ΄λΆμμ μ μμ μΌλ‘ μλν μ μμΌλ μΈλΆ μμ‘΄μ±μΈ DBλΌκ³ ν΄λ μΈλΆ μμΈμΌλ‘ μκ°νμ§ μλλ€.
μΈλΆ API, λ°μ΄ν°λ² μ΄μ€ μλ², κ·Έλ¦¬κ³ λ€λ₯Έ ν¬νΈμμ λμνλ λ€λ₯Έ μ ν리μΌμ΄μ
λ±
μ ν리μΌμ΄μ
μ λμμ μν₯μ λ―ΈμΉ μ μλ μΈλΆ μμ‘΄μ±μ μΈλΆ μμΈμ΄λΌκ³ μκ°νκ³
μ΄μ λν΄ νλΉν μκ²¬μΈ κ² κ°λ€λ 리뷰λ λ°μ ν©λ¦¬μ μΈ μκ°μ κ°κΉλ€κ³ νλ¨ν μ μμλ€.
νμ§λ§ λͺ¨λ μν©λ§λ€ λ²μλ λ€λ₯Ό μ μκ³ κ°λ°μ μ λ΅μ μμΌλ μ°Έκ³ λ§ νκΈΈ λ°λλ€.
κ°μ§λ₯Ό μ¬μ©νλ©΄ μλ―Έκ° μμ§ μμκΉ? π
λ³ΈμΈμ κ°μ§ κ°μ²΄μΈ ν μ€νΈ λλΈμ ν μ€νΈ κ²°κ³Όλ μ€μ ꡬν체μ κ°μ²΄μ κ²°κ³Όμ λ€λ₯΄κΈ° λλ¬Έμ λ³ μλ―Έκ° μλ κ² μλκΉ? λΌκ³ μκ°νμλ€.
νμ§λ§ μ€μ λ‘ μ ν리μΌμ΄μ μ λν΄ ν μ€νΈλ₯Ό μμ±νλ©΄μ ν μ€νΈ λλΈμ νμμ±μ λλΌκ² λμλ€.
μλ₯Ό λ€μ΄ 0~10 μ¬μ΄μ λμλ₯Ό λ°μμν€λ generate() λ©μλλ₯Ό κ°μ§ RandomNumberGeneratorκ° μκ³ μΈλΆμμλ ν΄λΉ λμ κ°μ΄ 0~4λ©΄ false, 5~10μ΄λ©΄ trueλ₯Ό returnνλ λ‘μ§μ΄ μ‘΄μ¬νλ€κ³ κ°μ νμ.
μ΄λ¬ν λ‘μ§μ ν μ€νΈν΄μΌνλ μν©μμ, λμλ μ°λ¦¬κ° μ‘°μν μ μλ κ°μ΄κΈ° λλ¬Έμ ν μ€νΈλ₯Ό μμ±νκΈ° κ½€λ κ³€λν΄μ§λ€.
μ΄λ° κ²½μ° μ°λ¦¬λ ν μ€νΈ λλΈμ ν΅ν΄ κ°λ¨ν λ¬Έμ λ₯Ό ν΄κ²°ν μ μλ€.
NumberGeneratorStubμ λ§λ€κ³ generate() λ©μλμ returnκ°μ 0~10 μ€ ν μ€νΈμ νμν κ°μΌλ‘ μ§μ μ€μ νμ¬ μ°λ¦¬κ° μνλ νΉμ κ°μ μ»λλ‘ ν μ μλ€.
λ¬Όλ‘ ν΄λΉ κ²°κ³Όλ μ°λ¦¬κ° μ‘°μν κ°μ§μ΄μ§λ§, μ΄λ κ² ν΅μ κ° 100% κ°λ₯ν μν©μ΄ μλ λμλ§ μ μ ν νμ©νλ€λ©΄ ν μ€νΈλ₯Ό ν΅ν΄ κΈ°λ₯μ λν΄ μ½κ² νμ ν μ μκ³ , λ΄λΆμ μΌλ‘ μ΄λ»κ² λμνλ μ§ μ΄ν΄νλ κ²μ ν° λμμ μ€ μ μλ νλ₯ν ν μ€νΈλ₯Ό μμ±μ ν° λμμ μ€ κ²μ΄λ€.
μ΄λ λ― μ°λ¦¬κ° ν΅μ ν μ μλ μμΈμ λν΄μ ν μ€νΈ λλΈμ μ¬μ©ν λ, ν¨μ©μ μ»μ μ μμ κ²μ΄λ€.
π Test Doubleμ μ’ λ₯
μΆμ²: https://tecoble.techcourse.co.kr/post/2020-09-19-what-is-test-double/
ν μ€νΈ λλΈμ μ’ λ₯λ μμ κ°μ΄ κ½€λ λ€μνλ€.
π Dummy
λλ―Έλ μ΄λ ν λμλ νμνμ§ μμ§λ§, μ΄λ ν κΈ°λ₯μ μ¬μ©ν λ νΉμ κ°μ²΄μ μΈμ€ν΄μ€λ§μ΄ νμν λ μ¬μ©λλ€.
λ€μ λ§ν΄, λλ―Έλ λμνμ§ μμλ ν μ€νΈμ μ΄λ ν μν₯λ λ―ΈμΉμ§ μλ κ°μ²΄λ₯Ό λ»νλ€.
μμ λ₯Ό ν΅ν΄ μ νν μ¬μ© μν©μ μ΄ν΄λ³΄μ
Accelerator.java
public interface Accelerator {
int push();
}
μλμ°¨λ₯Ό μμΌλ‘ κ°κ²νκΈ° μν μλμ°¨μ ν(int)μ returnνλ push()λΌλ νμμ μ± μμ κ°μ§ Accelerator κ° μ‘΄μ¬νλ€.
RandomMoveAccelerator.java
public class RandomMoveAccelerator implements Accelerator {
public static final int MIN_ACCEL_POWER = 0;
public static final int MAX_ACCEL_POWER = 9;
public static final int MIN_MOVABLE_POWER = 4;
public int push() {
return RandomNumberUtils.generate(MIN_ACCEL_POWER, MAX_ACCEL_POWER);
}
}
μ ν리μΌμ΄μ μ νλ‘λμ μ½λλ push() λ©μλ μ€ν μμ, 0~9 μ¬μ΄μ λμλ₯Ό μμ±νμ¬ returnν΄μΌνλ€.
Car.java
public class Car {
private final CarName name;
private int position;
private final Accelerator accelerator;
public Car(String name, Accelerator accelerator) {
this.name = new CarName(name);
this.position = 0;
this.accelerator = accelerator;
}
public void pushAccelerator() {
moveForward(accelerator.push());
}
private void moveForward(int power) {
if (power >= RandomMoveAccelerator.MIN_MOVABLE_POWER) {
position++;
}
}
Car ν΄λμ€λ μ΄λ¬ν RandomMoveAcceleratorλ₯Ό μμ±μ μ£Όμ λ°μ, μ ν리μΌμ΄μ λ΄λΆμμ λλ€κ°μ νμ©νμ¬ positionμ μ¦κ°μν¨λ€.
νμ§λ§ ν μ€νΈμμ μ΄λ¬ν Car κ°μ²΄λ₯Ό μμ±ν λ, RandomMoveAcceleratorλ μ¬μ©νμ§ μμ§λ§, Car κ°μ²΄λ₯Ό μμ±νκΈ° μν΄ Acceleratorλ μ£Όμ ν΄μΌμ£Όμ΄μΌ νλ κ²½μ°μλ μ΄λ»κ² ν κΉ?
μ΄λ μ¬μ©νλ κ²μ΄ λλ―Έμ΄λ€.
BridgeGeneratorDummy.java
public class AcceleratorDummy implements Accelerator {
@Override
public int push() {
return 0;
}
}
μ΄λ¬ν μν©μ λΉλμ΄ λ³΄μμ λ, μμ κ°μ΄ μλ¬΄λ° λμλ νμ§ μλ AcceleratorDummy ν΄λμ€λ₯Ό ν΅ν΄ ”μ΄λ ν λμλ νμ§ μκ³ μΈμ€ν΄μ€ μ체λ§μ μ 곡νλ€” λΌλ Dummyμ μν μ λν΄ μ§κ΄μ μΌλ‘ μ΄ν΄ν μ μλ€.
- λ¬Όλ‘ return typeμ΄ intνμ΄κΈ° λλ¬Έμ 0μ returnνκΈ΄ νμ§λ§, μ΄λ ν λ‘μ§μ²λ¦¬λ νμ§ μμΌλ©° κ·Έμ 0μ 리ν΄νλ€.
- Dummyλ‘ μ¬μ©λ κ²μ΄κΈ° λλ¬Έμ push λΌλ λ©μλκ° μ¬μ©λ μΌμ΄ μλ κ²½μ°μλ§ μ¬μ©νλ€.
μ΄μ§νΌ μ€νμν€μ§ μμ κ±°λ©΄ νλ‘λμ μ½λμ ꡬνν΄λμ ꡬν체λ₯Ό μ¬μ©νλ©΄ λμ§ μμκΉ?
λ¬Όλ‘ κ°λ₯νλ€κ³ μκ°νλ€. νμ§λ§ μ΄ κΈ°μ€μ μν©μ λ°λΌ λ€λ₯Ό κ² κ°λ€.
νμ§λ§ λ§μ½ νλ‘λμ μ½λμ ꡬνν΄λμ ꡬνμ²΄κ° μ±κΈν€μΌλ‘ μ¬μ©λκ³ μλ€λ©΄, ν μ€νΈμμλ νλ‘λμ μ½λμμ μ¬μ©μ€μΈ μΈμ€ν΄μ€μ κ°μ μΈμ€ν΄μ€λ₯Ό μ¬μ©νκ² λλ€.
μ΄λ νλ‘λμ μ½λμ ꡬν체 λ΄λΆμ μ μ μΌλ‘ μνλ₯Ό κ°μ§κ³ μλ ν΄λμ€ λ³μκ° μλ€κ³ νλ©΄? ν μ€νΈμ λμμ΄ μ€μ μ ν리μΌμ΄μ μλμ μν₯μ λΌμΉ μλ μλ€.
μ΄λ¬ν κ²½μ°μ λλ―Έλ₯Ό μ¬μ©νλ©΄ μ μ νμ§ μλ μΆλ€.
π Fake
νμ΄ν¬ κ°μ²΄λ 볡μ‘ν λ‘μ§μ΄λ, κ°μ²΄μμ νμλ‘νλ λ€λ₯Έ μΈλΆ κ°μ²΄λ€μ λμμ λ¨μννμ¬ κ΅¬νν κ°μ²΄μ΄λ€.
νμ΄ν¬ κ°μ²΄μμ λ¨μνλ λμμ μ€μ νλ‘μ°μ μ μ¬νκ² κ΅¬νμ λμ΄ μμ§λ§, μ€μ νλ‘λμ μ½λμλ μ ν©νμ§ μλ μ½λμ΄λ€.
μμ λ₯Ό ν΅ν΄ μμΈν μ΄ν΄λ³΄μ
μμ μ½λ
MemberRepository.java
public interface MemberRepository {
Member save(Member member);
}
Member κ°μ²΄λ₯Ό μ λ ₯λ°μμ μ μ₯μμ μ μ₯νλ€λ νμμ μ± μμ κ°μ§ MemberRepository μΈν°νμ΄μ€μ save() λ©μλκ° μ‘΄μ¬νλ€κ³ κ°μ νμ.
MemberRepositoryImpl.java
public class MemberRepositoryImpl {
Member save(Member member) {
// DB μ μ₯ λ‘μ§..
}
}
μ€μ νλ‘λμ μ½λμμ MemberRepositoryImplμ΄λΌλ ꡬνμ²΄κ° Member κ°μ²΄λ₯Ό DBμ μ μ₯νλ λ‘μ§μ μνν κ²μ΄λ€.
κ·Έλ¦¬κ³ μ μ₯λλ Member μν°ν°μ PKλ 1λ²λΆν° μλμΌλ‘ μ¦κ°νλ Auto Increment μ€μ μ΄ λμ΄μλ€.
μ°λ¦¬λ μ΄μ μ΄ λ‘μ§μ λν΄ ν μ€νΈλ₯Ό μμ±ν΄λ³΄λ €κ³ νμ§λ§ λ¬Έμ λ₯Ό λ°κ²¬νκ² λλ€.
DBλ μ ν리μΌμ΄μ μλ²μ μΈλΆλ‘ λΆλ¦¬λμ΄ μλ€. λλ¬Έμ λ€νΈμν¬μ λ¬Έμ κ° λ°μνλ©΄, DBμ μ κ·Όν΄μ λ°μ΄ν°λ₯Ό μΆκ°νλ λ‘μ§μ ν μ€νΈνλ κ³Όμ μμ μλ¬κ° λ°μνλ€. λ€νΈμν¬μ λ°λΌ ν μ€νΈκ° μ€ν¨ν μλ μκ² λλ€λ κ²μ΄λ€.
μ΄λ¬ν λ€νΈμν¬ μν₯μ μμ λ©΄μ λκ°μ λμμ μννμ¬ ν μ€νΈ μ½λλ₯Ό ν΅ν΄ κΈ°λ₯μ΄ μ΄λ»κ² μλνλ μ§ μ§κ΄μ μΌλ‘ κ°λ°μμκ² μΈμμμΌμ£ΌκΈ° μν λ°©λ²μΌλ‘ 무μμ΄ μμκΉ?
μ΄λ μ¬μ©λλ κ²μ΄ λ°λ‘ Fake κ°μ²΄μ΄λ€.
FakeMemberRepository.java
public class FakeMemberRepository implements MemberRepository {
private static final Map<Long, Member> members = new ConcurrentHashMap<>();
private static Long idSequence = 1L;
@Override
public Member save(Member member) {
members.put(idSequence++, member);
return member;
}
}
FakeMemberRepositoryλ μ€μ DBκ° μλ Mapμ λ°μ΄ν°λ₯Ό μ μ₯ν¨μΌλ‘μ¨ λ°μ΄ν°κ° μ μ₯μμ μ μ₯λλ κ²κ³Ό, idSequenceλ₯Ό μ¬μ©ν¨μΌλ‘μ¨ Memberμ PKκ° Auto Increment λλ κ²μ μ νν ꡬνν Fake κ°μ²΄μ΄λ€.
μ΄λ¬ν λ΄λΆ ꡬν λ¨μνλ₯Ό ν΅ν΄ ν μ€νΈλ₯Ό νλ κ°λ°μμκ² DBμ μνλλ κ²κ³Ό λμΌν κ²°κ³Όλ₯Ό μ λ¬νλ©°, μΈλΆ μμΈμ μν₯μ λ°μ§ μκ³ νμ μ±κ³΅νλ ν μ€νΈλ₯Ό μμ±ν μ μλλ‘ λλ κ²μ΄ λ°λ‘ Fake κ°μ²΄μ μν μ΄λ€.
π Stub
μ€ν μ μμμ μκ°ν λλ―Έ κ°μ²΄κ° μ€μ λμνλ κ²μ²λΌ 보μ΄κ² λ§λ€μ΄λμ κ°μ²΄μ΄λ€.
μΈν°νμ΄μ€ λλ κΈ°λ³Έ ν΄λμ€κ° μ΅μνμΌλ‘λ§ κ΅¬νλ μνμ΄λ©°, ν μ€νΈμμ νΈμΆλ μμ²μ λν΄ λ―Έλ¦¬ μ€λΉλ κ²°κ³Όλ₯Ό μ 곡νλ€.
μ½κ² λ§ν΄ μ€ν μ, μν κ²μ¦μ μν ν μ€νΈ λλΈμ΄λ€.
μ 리νμλ©΄ λ΄λΆ λμμ λν ꡬνμ λͺ¨λ μ μΈνκ³ , λμμ λν κ²°κ³Όλ§μ μ»κ³ μΆμ λ μ¬μ©νλ€.
μλ μμ λ μ΄λ°μ κ°μ κ°μ²΄λ₯Ό μ¬μ©νλ©΄ μλ―Έκ° μμ§ μμκΉ? μμ μ€λͺ ν λ΄μ©κ³Ό λμΌν μμ μ΄λ€.
μμ λ₯Ό ν΅ν΄ μ€ν μ μ΄ν΄ν΄λ³΄μ
μμ μ½λ
Accelerator.java
public interface Accelerator {
int push();
}
μλμ°¨λ₯Ό μμΌλ‘ κ°κ²νκΈ° μν μλμ°¨μ ν(int)μ returnνλ push()λΌλ νμμ μ± μμ κ°μ§ Accelerator κ° μ‘΄μ¬νλ€.
RandomMoveAccelerator.java
public class RandomMoveAccelerator implements Accelerator {
public static final int MIN_ACCEL_POWER = 0;
public static final int MAX_ACCEL_POWER = 9;
public static final int MIN_MOVABLE_POWER = 4;
public int push() {
return RandomNumberUtils.generate(MIN_ACCEL_POWER, MAX_ACCEL_POWER);
}
}
μ ν리μΌμ΄μ μ νλ‘λμ μ½λλ push() λ©μλ μ€ν μμ, 0~9 μ¬μ΄μ λμλ₯Ό μμ±νμ¬ returnν΄μΌνλ€.
Car.java
public class Car {
private final CarName name;
private int position;
private final Accelerator accelerator;
public Car(String name, Accelerator accelerator) {
this.name = new CarName(name);
this.position = 0;
this.accelerator = accelerator;
}
public void pushAccelerator() {
moveForward(accelerator.push());
}
private void moveForward(int power) {
if (power >= RandomMoveAccelerator.MIN_MOVABLE_POWER) {
position++;
}
}
Car ν΄λμ€λ Accelerator μΈν°νμ΄μ€λ₯Ό ν΅ν΄ μ΄λ¬ν RandomMoveAcceleratorλ₯Ό μμ±μ μ£Όμ λ°κ³ , moveForward(int power) λ©μλλ₯Ό ν΅ν΄ λ΄λΆμμ λλ€κ°μ νμ©νμ¬ positionμ μ¦κ°μν¨λ€.
position μ¦κ°λ‘μ§μ λΆκΈ°μ²λ¦¬λ μλμ κ°λ€.
- λμκ° 0~4μ΄λ©΄ positionμ κ·Έλλ‘
- 5~10μ΄λ©΄ positionμ 1 μ¦κ°
νμ§λ§ moveForward(int power)λ λμμ μμ‘΄νκΈ° λλ¬Έμ moveForwardμ position μ¦κ° ν μ€νΈλ₯Ό μμ±ν λ, μ°λ¦¬κ° μνλ κ²°κ³Όλ₯Ό λ§λ€κΈ° μ΄λ €μ보μΈλ€.
ν μ€νΈλ₯Ό νκ² λ€κ³ privateμΈ moveForwardμ μ κ·Όμ μ΄μλ₯Ό publicμΌλ‘ λ³κ²½ν μλ μλ λ Έλ¦μ΄λ€.
μ΄λ΄ λ Stub κ°μ²΄λ₯Ό μ¬μ©νμ¬, μ°λ¦¬κ° μνλ κ°μ returnνλλ‘ κ΅¬ννλ©΄ moveForwardμ λν΄ μνλ κ²°κ³Όλ₯Ό λ§λ€μ΄λΌ μ μλ€.
StubAccelerator.java
public class StubAccelerator implements Accelerator {
private int power;
public StubAccelerator() {
this.power = 0; // NPE λ°©μ§λ₯Ό μν΄ κΈ°λ³Έκ° μ£Όμ
}
public void setPower(final int power) {
this.power = power;
}
public int push() {
return power;
}
}
μμ κ°μ΄ Acceleratorμ λν μ€ν μ μμ±νλ©΄ push() λ©μλκ° λλ€ κ°μ΄ μλ μ°λ¦¬κ° μ€μ ν κ°μ returnνλλ‘ λ§λ€ μ μλ€.
λ³΄ν΅ μ μ½λμ κ°μ΄ μνλ μ€μ κ°μ νλλ‘ λ§λ€μ΄λκ³ setterλ₯Ό ν΅ν΄ κ°μ μ€μ νλλ‘ κ΅¬ννλ€.
- μμ±μλ₯Ό ν΅ν΄ powerμ κ°μ μ§μ νλ λ°©λ²λ μκ² μ§λ§,
νλ‘λμ μ½λμ Accelerator ꡬν체λ powerλ₯Ό μΈμλ‘ μ λ ₯λ°λ μμ±μκ° μ‘΄μ¬νμ§ μλλ€.
λλ¬Έμ ν μ€νΈλ₯Ό μν΄ μλ‘μ΄ μΈμ€ν΄μ€ μμ± κ·μΉ(μμ±μ)μ λ§λ€μ΄μ£Όλ κ²μ ν μ€νΈ μ½λλ₯Ό ν΅ν΄ νλ‘λμ μ½λμ λμ λ‘μ§μ νμ νλ κ²μ νΌλμ μΌκΈ°ν μ μλ€.
λλ¬Έμ Stub μ¬μ©μ μμ΄μλ μμ±μλ³΄λ¨ Setter μ¬μ©μ μ§ν₯νμ!
π Spy
μ€νμ΄ κ°μ²΄λ μ€ν μ μν μ κ°μ§λ©΄μ κ°μ²΄μ μνλ₯Ό κ΄μ°°νκ³ κΈ°λ‘νλ λ° μ¬μ©λλ©° μ£Όλ‘ λ©μλ νΈμΆκ³Ό κ΄λ ¨λ μ 보λ₯Ό κΈ°λ‘νκ³ λ°ννλ€. μ΄λ νΉν ν μ€νΈ μ€μ κ°μ²΄κ° μ΄λ»κ² μνΈμμ©νλμ§ μΆμ νκ³ νμΈνλ λ° μ μ©νλ€.
μ€ν μ μν μ κ°μ§λ€κ³ ν΄μ μμ ν μ€ν κ³Ό λμΌν κ²μ μλλ€.
νΉμ λΆλΆμ μ€μ κ°μ²΄μ λμΌνκ² κ΅¬νν μ μκ³ , νΉμ λΆλΆμ μ€ν μΌλ‘ ꡬνν μ μλ€. κ·Έλ¦¬κ³ μ€ν μ μ΄λ ν νμμ λν κ²°κ³Όλ₯Ό μ»κΈ° μν΄ μ¬μ©νμ§λ§, μ€νμ΄ κ°μ²΄λ λ΄λΆ λ‘μ§μ μ¨μ΄μ μ€ν νμ λ±μ κ°μ²΄μ μνλ₯Ό κ΄μ°°νκ³ κΈ°λ‘νλ μν μ νλ€.
μ€μ κ°μ²΄μ λμΌνκ² λ‘μ§μ ꡬννλ μ΄μ λ λ‘μ§μ μ€ν μλ λ±μ 체ν¬ν΄μΌνλ μν©μΌ λ― μΆλ€. λ¬Όλ‘ μ€μ κ°μ²΄μ λμΌνκ² λμνλλ‘ κ΅¬νν νμκ° μκ±°λ, ꡬνν μ μλ λΆλΆμ λν΄μλ μ€ν μΌλ‘ ꡬνν΄λ λλ€.
κ²°λ‘ μ μΌλ‘ ꡬνμ μ€μ κ°μ²΄μ μ€ν μ¬μ΄μμ νμν κ²μ μ·¨ν΄μ λ§λ€λ©΄ λλ κ²μ΄κ³ , κ°μ²΄μ λ΄λΆμμ μ΄λ ν μ 보λ₯Ό μΈ‘μ νκ±°λ κΈ°λ‘νκΈ° μν΄ μ¬μ©λλ κ°μ²΄μΈ κ²μ΄λ€.
μμ μ½λ
SpyRandomMoveAccelerator.java
public class SpyRandomMoveAccelerator implements Accelerator {
public static final int MIN_ACCEL_POWER = 0;
public static final int MAX_ACCEL_POWER = 9;
public static final int MIN_MOVABLE_POWER = 4;
private int calledCount = 0;
public int push() {
calledCount++;
return RandomNumberUtils.generate(MIN_ACCEL_POWER, MAX_ACCEL_POWER);
}
public int getCalledCount() {
return calledCount;
}
}
μ μ½λλ RandomMoveAcceleratorμ Spy κ°μ²΄μ΄λ€.
μμμ μκ°ν RandomMoveAccelerator ν΄λμ€μ λκ°μ΄ μλνμ§λ§, λ΄λΆμ μΌλ‘ calledCount λΌλ μ μ μλ£νμ΄ push() λ©μλμ νΈμΆ νμλ₯Ό κΈ°λ‘νλ€.
λν getCalledCount() λ©μλλ₯Ό ν΅ν΄ push() λ©μλκ° μΌλ§λ νΈμΆ λμλ μ§ νμΈν μ μλ€.
μ΄λ κ² λ©μλμ νΈμΆ νμ λ±κ³Ό κ°μ κ°μ²΄μ νμ λλ μν λ±μ κ΄μ°°νκ³ κΈ°λ‘νλ μν μ νλ κ°μ²΄κ° λ°λ‘ μ€νμ΄ κ°μ²΄μ΄λ€.
π Mock
Mockμ΄λ νκΈλ‘ λͺ¨μμ, κ°μ§μ λΌλ λ»μ κ°μ§λ ν μ€νΈ λλΈ κ°μ²΄λ‘, μ€μ κ°μ²΄μ λμΌν λͺ¨μ κ°μ²΄λ₯Ό λ§λ€μ΄ ν μ€νΈμ ν¨μ©μ± λμ΄κΈ° μν΄ μ¬μ©νλ€.
μνλ₯Ό κ²μ¦νλ Stubκ³Όλ λ€λ₯΄κ², μ΄λ ν νμλ₯Ό μ μννλ μ§μ λν΄ κ²μ¦νλ νμ κ²μ¦ μ μν ν μ€νΈ λλΈ κ°μ²΄μ΄λ€.
Javaνκ²½μμ μ£Όλ‘ Mockitoλ₯Ό ν΅ν΄ ν μ€νΈλ₯Ό μννκ² λλ€.
Mockitoλ?
mockμ μ½κ² λ§λ€κ³ mockμ νλμ μ νλ stubbing, μ μμ μΌλ‘ μλνλ μ§ κ²μ¦νλ verify λ± λ€μν κΈ°λ₯μ μ 곡ν΄μ£Όλ νλ μμν¬μ΄λ€.
DBμ°λ μμ λ±κ³Ό κ°μ ν μ€νΈ μλνκ° μ΄λ ΅κ±°λ, μμ²μ μκ°μ΄ μ€λ 걸리λ λ΄μ©λ€μ Mockitoλ₯Ό ν΅ν΄ κ°μ§ κ°μ²΄λ₯Ό μμ±νμ¬ νμμ λν κ²μ¦μ μ μνκ² μννλ€.
μμ μ½λ
(μ μ©ν΄λ³΄κ³ μμ±)
κ²°ν¨ λ΄μ±
(νμ΅ν΄μ μ±μ°κΈ°)
'BackEnd' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
μ€νλ§λΆνΈμ Nginx 리λ²μ€ νλ‘μ(Reverse Proxy) μλ² μ°κ²°νκΈ° (0) | 2024.05.20 |
---|---|
νλ‘μ(Proxy) μλ²λ? (0) | 2024.05.19 |
[μΈμ¦/μΈκ°] RefreshTokenμ μ Redisλ₯Ό μ¬μ©ν΄ κ΄λ¦¬ν κΉ? (with. RTR λ°©μ) (5) | 2023.06.13 |
WAS(Web Application Server)λ 무μμΈκ° (0) | 2023.01.02 |
μ μμΌκ³Ό ν μ€νΈ λ°©λ²λ‘ (TDD & BDD) (1) | 2022.06.29 |