π[ko] Enhancing Test Reliability with TestContainers: Setting Up a Production-like Environment.
μ¬μ΄λ νλ‘μ νΈ, λ€λ¦μ ν μ€νΈ νκ²½ ꡬμΆκΈ° (with. TestContainer)
Using TestContainers allows developers to create reliable test environments that mimic production.
λ λΉ λ₯΄κ² λ¬λ¦¬κΈ° μν΄ μ κΉ λ©μΆλ€..
μ½κ° λͺ¨μμ΄ λλ λ¬Έμ₯μ΄κΈ°λ νλ°μ,
μ΄λ² ν¬μ€ν μ μ£Όμ κ° ν μ€νΈ μ½λλΌλ κ²μ μκ³ λ€μ μ λͺ©μ μ½μ΄λ³Έλ€λ©΄
μ΄λμ λλ λ€λ€ 곡κ°μ΄ κ° λ§ν μ λͺ©μ΄λΌκ³ μκ°ν©λλ€. (π ν¬ν )
μλ 10μμΈκ°μ?
κ·ΈλλΆν° μμν μ¬μ΄λ νλ‘μ νΈμΈ λνΌλ‘
λ 2 κ°μ μμ κΈ°ν/κ°λ°/λμμΈμ΄ μλ£λμ΄
λ°λͺ¨ μ΄νμ μμ°ν μ μμ΄μΌ νμ΄μ.
μ€κ°μ κΈ°νμ΄ λ³κ²½λκΈ°λ νκ³
μμ° μ§μ κΉμ§λ μλ‘μ΄ μꡬμ¬νμ΄ μΆκ°λκ±°λ κΈ°μ‘΄ κΈ°λ₯ μ€νμ΄ μμ λλ μΌμ΄ λ§€μ° λ§μκΈ° λλ¬Έμ
μ¬μ€μ ν μ€νΈ μ½λμ ν μ ν μκ°κ³Ό μ¬λ ₯μ΄ μμλ κ² κ°μμβ¦
ν΄μ»€ν€ κ°μ λλμΌλ‘ ν루 ν루 κ°λ°νλ κ² κ°μ΅λλ€.
μλ²½ν DDD (λ°λλΌμΈ μ£Όλ κ°λ°) μ΄μμ£ γ γ γ γ γ γ γ
μλ νλ°κΈ°λ₯Ό λΆνμ λ μ¬μ΄λ νλ‘μ νΈ λνΌλ‘λ,
μ¬ 2μλΆν° λ€μ λ¬λ €λ³΄κΈ°λ‘ νμ΅λλ€.
μ π ~
μλ νλ°κΈ° 2κ°μ κ°,
μμ¬λ²λ¦° κΈ°μ λΆμ±λ₯Ό 리μ€νΈμ νκ³ νλνλ ν΄κ²°ν΄λκ°λ μ€μΈλ°μ
μ΄λ²μ μ΄μΌκΈ°ν λ΄μ©μ ν μ€νΈ νκ²½ ꡬμΆμ λλ€. (λλ₯)
ν μ€νΈ νκ²½..?
κ·Έκ±° κ·Έλ₯ νλ©΄ λλκ±° μλμΌ..?
λΌκ³ μκ°ν μ μμ§λ§, λνΌλ‘ λ°±μλμμλ μ¬μ€ λ§μ κ³ λμ μνμ°©μ€κ° μμλλ°μ..
μ°¨κ·Όμ°¨κ·Ό μκ°νλλ‘ νκ² μ΅λλ€.. π
μ λͺ©μ μ κΉ λ€μ 보면β¦
λ λΉ λ₯΄κ² λ¬λ¦¬κΈ° μν΄ μ κΉ λ©μΆκΈ°.
μ΄ λ¬Έμ₯μ,
ν μ€νΈ μ½λλ₯Ό μ μμ±ν΄μΌ νλ μ§ κ·Έ μ΄μ λ₯Ό ν¨μΆμ μΌλ‘ μμ£Ό μ λ΄κ³ μλ€κ³ μκ°ν©λλ€.
μμΌλ‘ κΈ°νμ΄ κ³ λνλλ©΄μ
κΈ°μ‘΄ κΈ°λ₯μ νμ₯μν€κ±°λ
μλ‘μ΄ κΈ°λ₯μ μΆκ°ν μΌμ΄ λΆλͺ λ§μμ§ κ² κ°μλ°μ,
(μλν λ ν μ€νΈ μ½λλ μλ€κ³ κ°μ )
A μμμ μ΄μ¬ν μλμΌλ‘ ν
μ€νΈν΄μ 보μ₯λ κΈ°λ₯
μ΄ λμλ€κ³ ν΄λ΄
μλ€.
κ·Έλ¦¬κ³ κ³ λν μμ μ μ§ννλ©° Aβ κΈ°λ₯μ νμ₯νμμ΄μ.
λ¬Όλ‘ Aμ Aβ μ΄ κ²ΉμΉμ§ μλ λΆλΆμ μλ‘ ν μ€νΈλ₯Ό μ§νν΄μΌκ² μ§λ§,
A μ Aβ μ΄ κ²ΉμΉλ λΆλΆλ λ λ€μ μλμΌλ‘ ν μ€νΈλ₯Ό ν΄μΌκ² μ£ .
μ΄νμ B λΌλ κΈ°λ₯μ μΆκ°νλ©΄,
μμ ν μλ‘μ΄ κΈ°λ₯μΈ B λΏλ§μ΄ μλλΌ A μ B κ° κ²ΉμΉλ ꡬκ°λ ν μ€νΈν΄μΌ ν΄μ.
κΈ°μ‘΄μ ν μ€νΈλ₯Ό νλ μμμ κ³μ λ°λ³΅μ μΌλ‘ ν μ€νΈνκ³ μλ λΉν¨μ¨μ μΈ μν©μ νμΈν μ μμ΄μ.
μμ κ°μ μν©μμλ κ²¬κ³ ν μμ€ν μ κ°λ°ν μ μμ κ² κ°μ΅λλ€.
μλ‘μ΄ μλΉμ€ νΌμ³λ₯Ό κ°λ°νλ €λ©΄, ν΄λΉ κ°λ° κ±΄μ΄ νμ¬ λμ μ€μΈ μ΄λ€ λΆλΆμ μν₯μ΄ κ° μ§
μλμΌλ‘ νμΈν΄μΌ νκΈ° λλ¬Έμ μμ°μ±μ΄ νμ ν λ¨μ΄μ§κ² μ£ .
λ§μ½..
μ μμ±λ, μλν λ ν μ€νΈ μ½λκ° μμλλΌλ©΄
μλ‘μ΄ κΈ°λ₯μ ꡬννκ±°λ, κΈ°μ‘΄ κΈ°λ₯μ μμ κ°μμλλΌλ μ ν λλ €μ μμ΄ κ°λ°ν μ μκ² μ£ .
λ 빨리 λ¬λ¦¬κΈ° μν΄, μ κΉ λ©μΆ°μΌ νλ€λ μλ―Έλ μ΄κ±°μμ.
μ°λ¦¬ μ¬μ΄λ νλ‘μ νΈμΈ λνΌλ‘
λ,
μλ 2κ°μ κ° λ°λͺ¨λ°μ΄ μΆμλΌλ λ¨κ±°λ¦¬ 거리 μ§μ£Όλ ν΄λμ§λ§
ν μ€νΈ νκ²½μ΄ μ ν ꡬμΆλμ΄μμ§ μμκΈ° λλ¬Έμ
λ λΉ λ₯΄κ² μ€λ λ¬λ¦΄ μ μλ μ¬λ ₯μ΄ λ¨μμμ§ μμμ΅λλ€.
κ·Έλμ μ§κΈμ μ κΉ λ©μΆκ³ , λ λ©λ¦¬ κ°κΈ° μν μ λΉλ₯Ό ν΄μΌν λλΌκ³ κ²°μ νμ£ .
μλ‘ μ΄ κΈΈμλ κ² κ°λ€μ.
μμ½νμλ©΄, μ¬μ΄λ νλ‘μ νΈ λνΌλ‘
μ κΈ°μ λΆμ± μ€ νλμΈ ν
μ€νΈ νκ²½ ꡬμΆμ μ§κΈ ν΄κ²°ν΄μΌλ§ νλ€.
μ΄κ±΄λ°μ..!
λνΌλ‘ λ°±μλμμ ν μ€νΈ νκ²½μ μ½κ² ꡬννμ§ λͺ»νκ² νλ νλ€μ 무μμ΄ μμμκΉμ?
λνΌλ‘μμ μ 곡νλ ν΅μ¬ κΈ°λ₯ μ€ νλλ νμ¬ μμΉλ₯Ό κΈ°λ°μΌλ‘ κ°κΉμ΄ λνΌμλ€μ μ‘°ννλ API μ λλ€.
κ°κ°μ μμΉλ μκ²½λ μ 보λ₯Ό κΈ°λ°μΌλ‘ μ‘°ννλ©°,
λνΌμμ μ¬μ©μ κ° κ±°λ¦¬ λν μ€μκ°μΌλ‘ κ³μ°μ΄ κ°λ₯ν΄μΌ νμ΅λλ€.
μμ κ°μ΄ λνΌλ‘λ κ³΅κ° λ°μ΄ν°λ₯Ό μ κ·Ήμ μΌλ‘ νμ©ν΄μΌ νλ κ²½μ°κ° λ§μμ΅λλ€.
κ³΅κ° λ°μ΄ν° κ΄λ ¨ νλΆν κΈ°λ₯μ μ 곡ν΄μ£Όλ mysql μ λ©μΈ λ°μ΄ν°λ² μ΄μ€ μμ§μΌλ‘ μ νν μ΄μ λ μ΄λλ¬Έμ΄μλλ°μ..!
( μΆνμ κ³΅κ° μΈλ±μ€ κ΄λ ¨ν 쿼리 νλ ν¬μ€ν μ΄ μμ λμ΄ μμ΅λλ€ ~ )
λ³΄ν΅ ν μ€νΈ νκ²½μμμ λ°μ΄ν°λ² μ΄μ€λ μ λ§ κ°νΈνκ² κ΅¬μΆν μ μλ h2 DB λ₯Ό λ§μ΄ μ¬μ©νμ£ .
λ€λ§ λνΌλ‘μμλ μ§κΈλ, μμΌλ‘λ mysql μμ μ 곡νλ κ³΅κ° λ°μ΄ν° νμ / ν¨μλ₯Ό μ κ·Ήμ μΌλ‘ νμ©νμ¬ μ±λ₯ κ°μ μ ν΄λκ° κ³νμ΄κΈ° λλ¬Έμ
H2 κΈ°λ°μ ν μ€νΈ νκ²½μΌλ‘λ μ μ½μ΄ λ§μμ΅λλ€.
ν μ€νΈ μ½λλ₯Ό μννκ² νκΈ° μν΄,
νλ‘λμ μ½λμμ mysql μ μμ‘΄μ μΈ ν¨μλ₯Ό μ¬μ©νμ§ μλ λ°©λ²λ μμλλ°μ
κ·Έλ¬κΈ°μλ mysql μμ μ 곡ν΄μ£Όλ μμΉ κΈ°λ° κΈ°λ₯μ΄ κ°λ ₯νκΈ° λλ¬Έμ μ’μ§ μλ€κ³ νλ¨νμ΅λλ€.
μλλ©΄ ν μ€νΈ νκ²½μμ ν΄λΉ κΈ°λ₯λ€μ λͺ¨λ mocking ν΄λ λ ν λ°μ,
μΈλΆ μμ€ν μ΄ μλ λνΌλ‘ μλΉμ€μ ν΅μ¬ κΈ°λ₯μΈλ° μ΄λ₯Ό mocking νλ κ² κ³Όμ° μ¬λ°λ₯Έ λ°©ν₯μΌκΉμ?
λΉμ°ν.. μλκ² μ£ .
κ·Έλ¬λ©΄ λ¨μ λ°©λ²μ λ¨ νλ.
ν μ€νΈ νκ²½μ h2 κ° μλ mysql μ μ¬μ©νλ©΄ λλκ±°μ£ ! (λΉμ°)
μ κ·ΈλΌ λ¬Έμ μ μκ° μ‘°κΈ λ°λμλ€μ.
ν
μ€νΈ νκ²½μμ mysql μ μ΄λ»κ² ꡬμΆνλ©΄ μ’μκΉμ?
κ°μ λ‘컬μ mysql μ demon μΌλ‘ μ€νμν¨ λ€, νλ‘λμ db λ₯Ό dump ν΄μ μ¬μ©νλλ‘ νλ©΄ μ΄λ¨κΉμ?
ν β¦
λ무 λ‘컬 νκ²½μ μμ‘΄μ μ΄μ£ .
βμ€ μ»΄μμ ν
μ€νΈκ° λ€ μ±κ³΅νλλ° μ μ μλλκ±°μ£ ?β
νλ‘λμ db μ μ€ν€λ§λ₯Ό νμ λκΈ°νν΄μ£Όμ΄μΌ νλ€λ κ΄λ¦¬ν¬μΈνΈλ νλ λμ΄λ©λλ€..
ν μ€νΈ νκ²½ ꡬμΆμ΄ λ§€μ° κ°νΈνκ³ νΈλ¦¬ν΄μΌ,
λ λ§μ μκ°μ ν μ€νΈ μ½λμ ν μ νλλ‘ μ λν μ μλ€κ³ μκ°νκΈ° λλ¬Έμ
μ΄ λ°©λ²μ κΈ°κ°νμ΅λλ€.
μ..
λ€λ₯Έ μ’μ λ°©λ²μ΄ μμκΉμ?
λ‘컬 νκ²½μ.. μ’ μμ μ΄μ§ μμ ν μ€νΈ νκ²½μ΄λΌ..
μ μ΄κ±° μμ 컨ν μ΄λ κ°λ μλκ°μ? (λλ₯)
ν μ€νΈλ₯Ό run νλ©΄
ν μ€νΈ μ©λμ λ컀 컨ν μ΄λκ° λμμ§κ³
ν μ€νΈκ° λλλ©΄ 컨ν μ΄λλ₯Ό λ΄λ €μ£Όλ©΄ λκ² λ€μ!
λΌκ³ μκ°νκ³ λ°λ‘ ꡬκΈλ§ν΄λ³΄μλλ°,
μ νν μΌμΉνλ κ°λ μ ꡬνν΄λμ λΌμ΄λΈλ¬λ¦¬κ° μλλΌκ΅¬μ.. ( μλκ²μλ€μ.. )
ν μ€νΈ 컨ν μ΄λ(TestContainers)
ν μ€νΈ 컨ν μ΄λλ₯Ό μ΄μ©νλ©΄, μλ° μ½λλ§μΌλ‘ ν μ€νΈ μ© λ컀 μ΄λ―Έμ§λ₯Ό μμ£Ό μμ£Ό νΈλ¦¬νκ² μ μ΄ν μ μμ΄μ.
μ΄λ² ν¬μ€νΈμμ λ€λ£¨λ mysql λΏλ§μ΄ μλλΌ, mongoDB, Kafka μ κ°μ κ΄λ¦¬ μμ€ν λ€λ λͺ¨λ λ€λ£° μ μμΌλ―λ‘ μ€μ μλΉμ€ νκ²½κ³Ό λ§€μ° μ μ¬νμ§λ§ 격리λ νκ²½μμ ν μ€νΈλ₯Ό μ§νν μ μμ£ .
λ¨μ μ λ‘컬 νκ²½μμ λμ»€κ° λμνκ³ μμ΄μΌ νλ€λ μ κ³Ό,
ν μ€νΈ μμν λ 컨ν μ΄λλ₯Ό λμ°λ μ λμ μμ μκ°μ΄ λμ΄λλ€λ μ μ΄ μμ΄μ.
νμ§λ§,
λͺ¨λ κ°λ°μλ€μ λ‘컬 νκ²½μ μ ν μ’ μμ μ΄μ§ μκ³ , λ§€μ° κ°λ¨νκ³ νΈλ¦¬νκ² μ€μ μλΉμ€μ μ μ¬ν ν μ€νΈ νκ²½μ ꡬμΆν μ μλ€λ μμ£Ό ν° μ₯μ μ΄ μκΈ° λλ¬Έμ μ λ¨μ λ€μ μ΄λμ λ κ°μμ΄ κ°λ₯νλ€κ³ μκ°νμ΅λλ€.
λμνλ λͺ¨μ΅μ λ¨Όμ λ³ΌκΉμ?
ν μ€νΈ μ½λλ₯Ό μ€νμν€λ©΄,
미리 μ€μ ν΄λ 컨ν μ΄λκ° μ€νλλ κ²μ νμΈν μ μμ΄μ.
κ·Έλ¦¬κ³ ν΄λΉ 컨ν μ΄λ νκ²½μμ ν μ€νΈλ₯Ό μ§νν μ μμ£ .
mysql 컨ν μ΄λλ₯Ό λμ κΈ° λλ¬Έμ, mysql μμ μ 곡νλ μμΉ λ°μ΄ν° νμ μΈ Point μ μμΉ ν¨μμΈ ST_DISTANCE_SPHERE μ μ¬μ©ν μλΉμ€ λ‘μ§μ ν μ€νΈ ν μ μκ² λμλ€μ!
( ST_DISTANCE_SPHERE
μ μ¬μ©νλ©΄ μΏΌλ¦¬κ° κ³΅κ° μΈλ±μ€ R-tree
λ₯Ό νμ§ λͺ»νλ€λ μ΄μκ° μλλ°, μ΄λ μΆν ν¬μ€ν
μμ κ³΅κ° μΏΌλ¦¬ κ°μ μ£Όμ λ‘ λ€μ λ€λ€λ³Ό μμ μ΄μμ!! μ¬μ€ μ λ°μ μΌλ‘ λΉν¨μ¨μ μΈ μΏΌλ¦¬κ° λλΆλΆμ΄
κΈ° λλ¬Έμ, μ 체μ μΌλ‘ 쿼리λ₯Ό κ°μμμ΄λ³΄λ €κ³ ν©λλ€.. λλ΅ 4~5μ μμ λͺ¨λ κ΅μ²΄ν΄λ²λ¦¬κ³ μΆλ€μ..γ
γ
)
ν μ€νΈ 컨ν μ΄λλ₯Ό μ¬μ©νκΈ° μν΄μλ μλμ μμ‘΄μ±μ λ°μμ£Όμ΄μΌ ν©λλ€.
testImplementation 'org.testcontainers:junit-jupiter:1.19.0'
testImplementation 'org.testcontainers:mysql'
κ·Έλ¦¬κ³ μλμ κ°μ΄ ν΄μ£Όλ©΄
@Container
MySQLContainer mySQLContainer = new MySQLContainer("mysql:8");
mysql:8 μ΄λ―Έμ§λ‘ λ컀 컨ν μ΄λλ₯Ό λμμ£Όκ³ , ν μ€νΈκ° λλλ©΄ μ’ λ£μμΌμ€λλ€.
λ€λ§, λ§€λ² λͺ¨λ ν μ€νΈμ λν΄μ 컨ν μ΄λλ₯Ό λμμ£Όκ³ λ΄λ €μ£Όλ μμ μ λ°λ³΅νλ€ λ³΄λ μ 체μ μΈ ν μ€νΈ μ½λ μ€νμκ°μ΄ λ§μ΄ μ§μ²΄λκ² μ£ .
μ΄λ₯Ό ν΄κ²°νκΈ° μν΄ μ»¨ν μ΄λλ₯Ό static νλλ‘ μ μΈνκ³ μ΄κΈ°νν΄μ£Όλλ‘ ν©μλ€.
κ° μ»¨ν
μ΄λλ§λ€ νμν νκ²½ λ³μλ @DynamicPropertySource
μ ν΅ν΄ λμ μΌλ‘ μ£Όμ
λ°μ μ μλλ°μ,
λνΌλ‘μμλ μλμ κ°μ΄ μ¬μ©νκ³ μμ΄μ!
@Slf4j
@SpringBootTest(classes = ServiceIntegrationTestConfiguration.class)
@Import({CoreTestConfiguration.class})
public abstract class ServiceIntegrationTestBase {
private static final String REDIS_DOCKER_IMAGE = "redis:5.0.3-alpine";
private static final String MYSQL_DOCKER_IMAGE = "mysql:8.0";
private static final String MYSQL_ROOT = "root";
private static final String MYSQL_PASSWORD = "1234";
private static final int REDIS_PORT = 6379;
@Container
protected static MySQLContainer mySQLContainer;
@Container
protected static GenericContainer redisContainer;
@DynamicPropertySource
static void configureProperties(final DynamicPropertyRegistry registry) {
// mysql env init
log.info("""
\n
β
mysql property λ₯Ό μ£Όμ
ν©λλ€.
""");
registry.add("spring.datasource.url", mySQLContainer::getJdbcUrl);
registry.add("spring.datasource.username", () -> MYSQL_ROOT);
registry.add("spring.datasource.password", () -> MYSQL_PASSWORD);
// redis env init
log.info("""
\n
β
redis property λ₯Ό μ£Όμ
ν©λλ€.
""");
registry.add("spring.redis.host", redisContainer::getHost);
registry.add("spring.redis.port", () -> "" + redisContainer.getMappedPort(REDIS_PORT));
}
static {
// mysql test container init
mySQLContainer = (MySQLContainer) new MySQLContainer(MYSQL_DOCKER_IMAGE)
.withUsername(MYSQL_ROOT)
.withPassword(MYSQL_PASSWORD)
.withDatabaseName("test")
.withEnv("MYSQL_ROOT_PASSWORD", MYSQL_PASSWORD);
log.info("""
\n
π³ MYSQL ν
μ€νΈ 컨ν
μ΄λλ₯Ό μμν©λλ€.
- base image: {}
""", MYSQL_DOCKER_IMAGE);
mySQLContainer.start();
// redis test container init
redisContainer = new GenericContainer<>(REDIS_DOCKER_IMAGE)
.withExposedPorts(REDIS_PORT)
.withReuse(true);
log.info("""
\n
π³ Redis ν
μ€νΈ 컨ν
μ΄λλ₯Ό μμν©λλ€.
- base image: {}
""", REDIS_DOCKER_IMAGE);
redisContainer.start();
}
}
μλΉμ€ λ μ΄μ΄ ν΅ν© ν μ€νΈλ λͺ¨λ μ ν΄λμ€λ₯Ό μμλ°λλ‘ ν΄μ,
Spring Context λ₯Ό μ€λ³΅μΌλ‘ λμμ λ°μνλ μκ° μ§μ°μ μ΅μννλ €κ³ ν©λλ€.
μμλ‘ μμ±ν΄λ ν μ€νΈ μ½λλ μλμ κ°μμ!
public class ShelterServiceTest extends ServiceIntegrationTestBase {
@Autowired
private ShelterService shelterService;
@Autowired
private ShelterRepository shelterRepository;
@DisplayName("1000 m μ΄λ΄μ μμΉν μ£Όλ³ λνΌμ 리μ€νΈλ₯Ό μ‘°νν μ μμ΅λλ€.")
@Test
void getNearestShelterTest() {
// given
shelterRepository.save(Shelter.of(ShelterType.CIVIL_DEFENCE, "1000m μ΄λ΄μ λνΌμ λ―Όλ°©μλνΌμ", 35.504, 35.5));
shelterRepository.save(Shelter.of(ShelterType.CIVIL_DEFENCE, "1000m λ³΄λ€ λ¨Ό λνΌμ", 36.504, 36.5));
// when
NearbyShelterListResponse response = shelterService.getNearbyShelterList(NearbyShelterRequest.of(35.5, 35.5, "λ―Όλ°©μ"));
// then
Assertions.assertThat(response.getCount()).isEqualTo(1);
}
}
μ¬μ€ μμ μμ±λ κ°λ¨ν ν μ€νΈ μ½λλ§ λ³΄κ³ λ, νλ‘λμ μ½λμμ κ°μ ν΄μΌ ν μ μ νλ μ°ΎμλΌ μ μμ΄μ.
무μμΌκΉμ?
λ°λ‘, 1000m μ΄λ΄λΌλ 쑰건μΈλ°μ..!!
μ ν μ€νΈμ½λλ₯Ό 보면 μ§μν μ μκ² μ§λ§ Query λ 벨μμ where μ μ 1000 m μ΄νμΈ λ μ½λλ§ μ‘°ννλλ‘ νκ³ μμ΄μ.
μ΄λ³΄λ€λ, 1000 μ΄λΌλ κ°μ μΈλΆμ νλΌλ―Έν°λ‘λΆν° μ£Όμ λλλ‘ νλ©΄
μ‘°κΈ λ ν μ€νΈκ° μ¬μμ§λ μ½λκ° λ¨κ³Ό λμμ νλ‘λμ μ½λλ λ μ μ°ν΄μ§μ§ μμκΉμ?
μ΄μ κ°μ΄ ν μ€νΈ μ½λλ₯Ό μμ±νλ€ λ³΄λ©΄,
λ―Έμ² λ°κ²¬νμ§ λͺ»νλ νλ‘λμ μ½λ μμ λ¬Έμ μ μ΄ λμ 보μ΄κ² λλ€λ μμ£Ό μ’μ μ₯μ μ΄ μμ΄μ..!
ν μ€νΈ μ½λλ₯Ό μμ±ν μ μλ νκ²½μ ꡬμ±νμΌλ,
λΉλΆκ°μ ν μ€νΈ μ½λλ₯Ό μμ±νλ©°
νλ‘λμ μ½λμ λ¬Έμ μ μ μ λλ‘ μ§λ¨ν΄λ³΄λ €κ³ ν©λλ€.
Leave a comment