0523 ~ 0605


# 0523 ~ 0605

# 0525 - ๋‹จ์œ„ ํ…Œ์ŠคํŠธ, ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ, ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ

# ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (Unit Test)

๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋Š” ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—์„œ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•œ ๊ฐ€์žฅ ์ž‘์€ ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์˜ˆ์ƒ๋Œ€๋กœ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ…Œ์ŠคํŠธ

๋‹จ์œ„ ํ…Œ์ŠคํŠธ์—์„œ ํ…Œ์ŠคํŠธ ๋Œ€์ƒ ๋‹จ์œ„์˜ ํฌ๊ธฐ๋Š” ์—„๊ฒฉํ•˜๊ฒŒ ์ •ํ•ด์ ธ ์žˆ์ง€ ์•Š๋‹ค. ํ•˜์ง€๋งŒ, ์ผ๋ฐ˜์ ์œผ๋กœ ํด๋ž˜์Šค ๋˜๋Š” ๋ฉ”์†Œ๋“œ ์ˆ˜์ค€์œผ๋กœ ์ •ํ•ด์ง„๋‹ค. ๋‹จ์œ„์˜ ํฌ๊ธฐ๊ฐ€ ์ž‘์„์ˆ˜๋ก ๋‹จ์œ„์˜ ๋ณต์žก์„ฑ์ด ๋‚ฎ์•„์ง„๋‹ค. ๋”ฐ๋ผ์„œ, ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋™์ž‘์„ ํ‘œํ˜„ํ•˜๊ธฐ ๋” ์‰ฌ์›Œ์ง„๋‹ค. ์ฆ‰, ํ…Œ์ŠคํŠธ ๋Œ€์ƒ ๋‹จ์œ„์˜ ํฌ๊ธฐ๋ฅผ ์ž‘๊ฒŒ ์„ค์ •ํ•ด์„œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ตœ๋Œ€ํ•œ ๊ฐ„๋‹จํ•˜๊ณ  ๋””๋ฒ„๊น…ํ•˜๊ฒŒ ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.

์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ๊ฐœ๋ฐœํ•  ๋•Œ, ์†Œํ”„ํŠธ์›จ์–ด ๋‚ด๋ถ€ ๊ตฌ์กฐ๋‚˜ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์„ ๊ณ ๋ คํ•˜์—ฌ ๊ฐœ๋ฐœ์ž๊ด€์ ์—์„œ ํ…Œ์ŠคํŠธํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋Š” ์†Œํ”„ํŠธ์›จ์–ด ๋‚ด๋ถ€ ์ฝ”๋“œ์— ๊ด€๋ จํ•œ ์ง€์‹์„ ๋ฐ˜๋“œ์‹œ ์•Œ๊ณ  ์žˆ์–ด์•ผ ํ•˜๋Š” ํ™”์ดํŠธ๋ฐ•์Šค ํ…Œ์ŠคํŠธ์ด๋‹ค. ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋Š” TDD์™€ ํ•จ๊ป˜ ํ•  ๋•Œ ํŠนํžˆ ๋” ๊ฐ•๋ ฅํ•ด์ง„๋‹ค.

@DisplayName("์ž๋™์ฐจ๊ฐ€ ์ „์ง„ํ•œ๋‹ค")
@Test
public void moveCar() {
    // given
    Car car = new Car("dani");

    // when
    car.move(4);

    // then
    assertThat(car.getPosition()).isEqualTo(1);
}

@DisplayName("์ž๋™์ฐจ๊ฐ€ ๋ฉˆ์ถ˜๋‹ค")
@Test
public void stopCar() {
    // given
    Car car = new Car("dani");

    // when
    car.move(3);

    // then
    assertThat(car.getPosition()).isEqualTo(0);
}

# ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ (Integration Test)

ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋Š” ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ณด๋‹ค ๋” ํฐ ๋™์ž‘์„ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ๋ชจ๋“ˆ๋“ค์„ ๋ชจ์•„ ์ด๋“ค์ด ์˜๋„๋Œ€๋กœ ํ˜‘๋ ฅํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ…Œ์ŠคํŠธ์ด๋‹ค.

ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋Š” ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์™€ ๋‹ฌ๋ฆฌ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” ๋ถ€๋ถ„(ex. ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)๊นŒ์ง€ ๋ฌถ์–ด ๊ฒ€์ฆํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. ์ด๋Š” DB์— ์ ‘๊ทผํ•˜๊ฑฐ๋‚˜ ์ „์ฒด ์ฝ”๋“œ์™€ ๋‹ค์–‘ํ•œ ํ™˜๊ฒฝ์ด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๊ฐ€ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์ด ์™„์ „ํ•˜๊ฒŒ ์ž‘๋™ํ•˜๋Š”๊ฑธ ๋ฌด์กฐ๊ฑด ์ฆ๋ช…ํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค.

ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์˜ ์žฅ์ ์€ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์—์„œ ๋ฐœ๊ฒฌํ•˜๊ธฐ ์–ด๋ ค์šด ๋ฒ„๊ทธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์—์„œ๋Š” ํ™˜๊ฒฝ ๋ฒ„๊ทธ(ex. ์‹ฑ๊ธ€ ์ฝ”์–ด CPU์—์„œ๋Š” ์ž˜ ์‹คํ–‰๋˜๊ฑฐ๋‚˜ ์ฟผ๋“œ ์ฝ”์–ด CPU์—์„œ๋Š” ์ž˜ ์‹คํ–‰๋˜์ง€ ์•Š์Œ)์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•œํŽธ, ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์˜ ๋‹จ์ ์€ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ณด๋‹ค ๋” ๋งŽ์€ ์ฝ”๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ ํšŒ์„ฑ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด๋‹ค. ๋˜, ์–ด๋””์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์‰ฝ์ง€ ์•Š์•„ ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ํž˜๋“ค๋‹ค๋Š” ์ ๋„ ์žˆ๋‹ค.

์Šคํ”„๋ง๋ถ€ํŠธ์—์„œ๋Š” ํด๋ž˜์Šค ์ƒ๋‹จ์— @SpringBootTest ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

@SpringBootTest
class SubwayApplicationTests {
    @Test
    void contextLoads() {
    }
}

# ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ (Acceptance Test)

์ธ์ˆ˜ํ…Œ์ŠคํŠธ๋Š” ์‚ฌ์šฉ์ž ์Šคํ† ๋ฆฌ(์‹œ๋‚˜๋ฆฌ์˜ค)์— ๋งž์ถฐ ์ˆ˜ํ–‰ํ•˜๋Š” ํ…Œ์ŠคํŠธ์ด๋‹ค.

์•ž์„  ๋‘ ํ…Œ์ŠคํŠธ๋“ค๊ณผ ๋‹ฌ๋ฆฌ ๋น„์ฆˆ๋‹ˆ์Šค ์ชฝ์— ์ดˆ์ ์„ ๋‘”๋‹ค. ํ”„๋กœ์ ํŠธ์— ์ฐธ์—ฌํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ํ† ์˜ํ•ด์„œ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋งŒ๋“ค๊ณ , ๊ฐœ๋ฐœ์ž๋Š” ์ด์— ์˜๊ฑฐํ•ด์„œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ œ์ž‘ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ๋‹ค๋ฅธ ์˜์‚ฌ์†Œํ†ต์ง‘๋‹จ์œผ๋กœ๋ถ€ํ„ฐ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋ฐ›์•„ ๊ฐœ๋ฐœํ•œ๋‹ค๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

์ธ์ˆ˜ ํ…Œ์ŠคํŠธ๋Š” ์• ์ž์ผ ๊ฐœ๋ฐœ๋ก ์—์„œ ํŒŒ์ƒํ–ˆ๋‹ค. ํŠนํžˆ, ์ต์ŠคํŠธ๋ฆผ ํ”„๋กœ๊ทธ๋ž˜๋ฐ(XP)์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์šฉ์–ด์ด๋‹ค. ์ด๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š”์ง€๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์™€๋Š” ๋ถ„๋ฅ˜๊ฐ€ ๋‹ค๋ฅด๋‹ค. ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์š”๊ตฌํ•˜๋Š” ๊ฒƒ์€ ๋ˆ„๊ฐ€, ์–ด๋–ค ๋ชฉ์ ์œผ๋กœ, ๋ฌด์—‡์„ ํ•˜๋Š”๊ฐ€์ด๋‹ค. ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค ๋ณด๋ฉด ์ด๋Ÿฐ ๊ธฐ๋Šฅ์€ API๋ฅผ ํ†ตํ•ด ๋“œ๋Ÿฌ๋‚œ๋‹ค. ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ๋Š” ์ฃผ๋กœ ์ด API๋ฅผ ํ™•์ธ์ธํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ด๋ค„์ง„๋‹ค.

๊ฒฐ๊ตญ, ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ๋Š” ์†Œํ”„ํŠธ์›จ์–ด ์ธ์ˆ˜๋ฅผ ๋ชฉ์ ์œผ๋กœ ํ•˜๋Š” ํ…Œ์ŠคํŠธ์ด๋‹ค. ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ์ธ์ˆ˜ํ•˜๊ธฐ ์ „์— ๋ช…์„ธํ•œ ์š”๊ตฌ์‚ฌํ•ญ(์ธ์ˆ˜ ์กฐ๊ฑด)๋Œ€๋กœ ์ž˜ ์ž‘๋™ํ•˜๋Š”์ง€ ๊ฒ€์ฆ์ด ํ•„์š”ํ•˜๋‹ค.

์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ์ธ์ˆ˜ํ•  ๋•Œ, ์†Œํ”„ํŠธ์›จ์–ด ๋‚ด๋ถ€ ๊ตฌ์กฐ๋‚˜ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์„ ๊ณ ๋ คํ•˜๊ธฐ๋ณด๋‹ค๋Š” ์‹ค์ œ ์‚ฌ์šฉ์ž ๊ด€์ ์—์„œ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. ๋”ฐ๋ผ์„œ, ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ๋Š” ์†Œํ”„ํŠธ์›จ์–ด ๋‚ด๋ถ€ ์ฝ”๋“œ์— ๊ด€์‹ฌ์„ ๊ฐ€์ง€์ง€ ์•Š๋Š” ๋ธ”๋ž™๋ฐ•์Šค ํ…Œ์ŠคํŠธ์ด๋‹ค. ์‹ค์ œ ์‚ฌ์šฉ์ž ๊ด€์ ์—์„œ ํ…Œ์ŠคํŠธ ํ•  ๋•Œ E2E(End-to-End) ํ˜•์‹์„ ์ด์šฉํ•ด์„œ ํ™•์ธํ•œ๋‹ค.

Java์—์„œ๋Š” RestAssured, MockMvc ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑ ํ•  ์ˆ˜ ์žˆ๋‹ค.

public static ExtractableResponse<Response> ํšŒ์›_์ƒ์„ฑ_์š”์ฒญ(MemberRequest memberRequest) {
    return RestAssured
            .given()
            .contentType(MediaType.APPLICATION_JSON_VALUE)
            .body(memberRequest)
            .when().post("/api/members")
            .then()
            .extract();
}

# 0526 - Single branch๋กœ Clone ํ›„, ์ƒˆ๋กœ์šด ๋ธŒ๋žœ์น˜ ์ถ”๊ฐ€

git์—์„œ ๋ธŒ๋žœ์น˜๊ฐ€ ๋งŽ์„๊ฒฝ์šฐ ํŠน์ • ๋ธŒ๋žœ์น˜๋งŒ ์ถ”์ ํ•˜๋„๋ก cloneํ•  ์ˆ˜ ์žˆ๋‹ค.

git clone -b <branch name> --single-branch <github url> <target directory>
git clone -b jaesungahn91 --single-branch https://github.com/jaesungahn91/jwp_qna

์œ„์™€ ๊ฐ™์ด cloneํ•œ ํ›„ ์ƒˆ๋กœ์šด ๋ธŒ๋žœ์น˜๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์œผ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ƒˆ๋กœ์šด ๋ธŒ๋žœ์น˜๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

git remote set-branches --add origin [remote-branch]
git fetch origin [remote-branch]:[local-branch]

# 0529 - ATDD, ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ

# ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ(Acceptance Test)๋ž€?

๋ช…์„ธ ๋“ฑ ์š”๊ตฌ ์‚ฌํ•ญ์ด ์ถฉ์กฑ๋˜๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๋น„์ฆˆ๋‹ˆ์Šค ์ธก๋ฉด์— ์ดˆ์ ์„ ๋งž์ถ˜ ํ…Œ์ŠคํŠธ๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ณดํ†ต ๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„์—์„œ ์ž‘์—…(๊ธฐ๋Šฅ)์ด ์™„์ „ํžˆ ์™„๋ฃŒ๋˜์—ˆ๋Š”์ง€ ๊ฒ€์‚ฌํ•˜๋Š”๋ฐ ์ˆ˜ํ–‰๋œ๋‹ค.
์š”๊ตฌ์‚ฌํ•ญ(์ธ์ˆ˜ ์กฐ๊ฑด)์ด ๋งŒ์กฑํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ณผ์ •์—์„œ, ์‹œ๋‚˜๋ฆฌ์˜ค์— ๋งž์ถฐ ํ…Œ์ŠคํŠธ๊ฐ€ ์ˆ˜ํ–‰๋œ๋‹ค. ์ด๋•Œ, ์ธ์ˆ˜ ์กฐ๊ฑด(Aceeptance Criteria)์ด ์‚ฌ์šฉ์ž ์Šคํ† ๋ฆฌ๋ฅผ ์‹œ๋‚˜๋ฆฌ์˜ค ํ˜•์‹์œผ๋กœ ํ‘œํ˜„๋˜๋ฉฐ ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ํ”„๋กœ์ ํŠธ์— ์ฐธ์—ฌํ•˜๋Š” ์‚ฌ๋žŒ๋“ค(๊ฐœ๋ฐœ์ž, ๊ธฐํš์ž ๋“ฑ)์˜ ํ† ์˜๋ฅผ ํ†ตํ•ด ๋‚˜์˜จ๋‹ค.
์‹œ๋‚˜๋ฆฌ์˜ค์˜ ์ค‘์ ์€ ๋ˆ„๊ฐ€, ์–ด๋–ค ๋ชฉ์ ์œผ๋กœ, ๋ฌด์—‡์„ ํ•˜๋Š”๊ฐ€ ์ด๋‹ค.

# ATDD, ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ

์ธ์ˆ˜ ํ…Œ์ŠคํŠธ๋ฅผ ๋จผ์ € ์ž‘์„ฑํ•œ ๋‹ค์Œ ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•
์‚ฌ์šฉ์ž(๊ณ ๊ฐ)-๊ฐœ๋ฐœ์ž-ํ…Œ์Šคํ„ฐ๊ฐ„์˜ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜์„ ๊ธฐ๋ฐ˜ํ•œ ๊ฐœ๋ฐœ ๋ฐฉ๋ฒ•
์• ์ž์ผ์˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ๋ฒ•๋ก  ์ค‘ ํ•˜๋‚˜๋กœ ์‚ฌ์šฉ์ž ์Šคํ† ๋ฆฌ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ธ์ˆ˜ ์กฐ๊ฑด์„ ๋„์ถœํ•˜์—ฌ ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•๋ก ์ด๋‹ค.

ATDD๋ฅผ ํ†ตํ•ด ์š”๊ตฌ์‚ฌํ•ญ๊ณผ, ์ž‘์—…์˜ ์ˆœ์„œ์™€ ๋ฒ”์œ„๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋‹ค. image


# 0531 - String.format

public static String format(String format, Object... args);
public static String format(Locale l, String format, Object... args);

String์˜ static ๋ฉ”์„œ๋“œ์ธ format ๋ฉ”์„œ๋“œ๋Š” ๋ฌธ์ž์—ด์˜ ํ˜•์‹์„ ์„ค์ •ํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค.

# 1. %d (= Integer Formatting)

  • 10์ง„์ˆ˜ integer์˜ ํ˜•์‹์„ ์„ค์ •ํ•  ๋•Œ ์ด์šฉํ•œ๋‹ค.
int i = 23;

System.out.println(String.format("%d_", i));
System.out.println(String.format("%5d_", i));
System.out.println(String.format("%-5d_", i));
System.out.println(String.format("%05d_", i));

// ์ถœ๋ ฅ
23_
   23_
23   _
00023_
int i = 123456789;

System.out.println(String.format("%,d_", i));
System.out.println(String.format("%,15d_", i));
System.out.println(String.format("%,-15d_", i));
System.out.println(String.format("%,015d_", i));

// ์ถœ๋ ฅ
123,456,789_
    123,456,789_
123,456,789    _
0000123,456,789_

# 2. %s (s= String Formatting)

  • ๋ฌธ์ž์—ด์˜ ํ˜•์‹์„ ์„ค์ •ํ•  ๋Œ€ ์ด์šฉํ•œ๋‹ค.
String str = "tete";

System.out.println(String.format("%s_", str));
System.out.println(String.format("%12s_", str));
System.out.println(String.format("%-12s_", str));
System.out.println(String.format("%.2s_", str));
System.out.println(String.format("%-12.2s_", str));
System.out.println(String.format("%12.2s_", str));

// ์ถœ๋ ฅ
tete_
        tete_
tete        _
te_
te          _
          te_

# 3. %f (= Floating point Formatting)

  • ์‹ค์ˆ˜ํ˜• ์ˆซ์ž ํ˜•์‹์„ ์„ค์ •ํ•  ๋•Œ ์ด์šฉํ•œ๋‹ค.
double n = 123.45678;

System.out.println(3.4);
System.out.println(n);
System.out.println();

System.out.println(String.format("%f_", 3.4));
System.out.println(String.format("%f_", n));
System.out.println(String.format("%.6f_", n));
System.out.println(String.format("%15f_", n));
System.out.println(String.format("%-15f_", n));
System.out.println(String.format("%.3f_", n));
System.out.println(String.format("%.2f_", n));
System.out.println(String.format("%15.2f_", n));
System.out.println(String.format("%-15.2f_", n));
System.out.println(String.format("%015f_", n));
System.out.println(String.format("%015.2f_", n));

// ์ถœ๋ ฅ
3.4
123.45678

3.400000_
123.456780_
123.456780_
     123.456780_
123.456780     _
123.457_
123.46_
         123.46_
123.46         _
00000123.456780_
000000000123.46_

# 4. Locale ์„ค์ •

  • ์˜ค๋ฒ„๋กœ๋”ฉ๋œ String.format(Locale, ํฌ๋งท, ๊ฐ’); ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ตญ๊ฐ€๋ณ„ ํฌ๋งท ์„ค์ •์ด ๊ฐ€๋Šฅ.
int money = 35000;
Date today = new Date();

System.out.println(String.format("๏ฟฆ %,d", money));
System.out.println(String.format(Locale.GERMANY, "%,d โ‚ฌ", money));
System.out.println(String.format("%tp", today));
System.out.println(String.format(Locale.ENGLISH, "%tp", today));

// ์ถœ๋ ฅ
๏ฟฆ 35,000
35.000 โ‚ฌ
์˜คํ›„
pm

# 0602 - JPA ์—ฐ๊ด€๊ด€๊ณ„ ํŽธ์˜ ๋ฉ”์„œ๋“œ

# ์—ฐ๊ด€๊ด€๊ณ„ ํŽธ์˜ ๋ฉ”์„œ๋“œ

์–‘๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ๋งบ์„ ๋•Œ์—๋Š”, ์–‘์ชฝ ๋ชจ๋‘ ๊ด€๊ณ„๋ฅผ ๋งบ์–ด์ฃผ์–ด์•ผํ•œ๋‹ค. ์‚ฌ์‹ค JPA์˜ ์ž…์žฅ์—์„œ ๋ณด์•˜์„ ๋•Œ์—๋Š” ์™ธ๋ž˜ํ‚ค ๊ด€๋ฆฌ์ž(์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ)์ชฝ์—๋งŒ ๊ด€๊ณ„๋ฅผ ๋งบ์–ด์ค€๋‹ค๋ฉด ์ •์ƒ์ ์œผ๋กœ ์–‘์ชฝ ๋ชจ๋‘์—์„œ ์กฐํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

Team team1 = new Team("Team1");
em.persist(team1);

Member member1 = new Member("Member1");
member1.setTeam(team1); // ์—ฐ๊ด€๊ด€๊ณ„ ์„ค์ • member1 -> team1

ํ•˜์ง€๋งŒ ๊ฐ์ฒด๊นŒ์ง€ ๊ณ ๋ คํ•œ๋‹ค๋ฉด, ์–‘์ชฝ ๋‹ค ๊ด€๊ณ„๋ฅผ ๋งบ์–ด์•ผํ•œ๋‹ค.

Team team1 = new Team("Team1");
em.persist(team1);

Member member1 = new Member("Member1");
member1.setTeam(team1); // ์—ฐ๊ด€๊ด€๊ณ„ ์„ค์ • member1 -> team1
team1.getMembers().add(member1) // ์—ฐ๊ด€๊ด€๊ณ„ ์„ค์ • tema1 -> member1

์ฆ‰, ๊ฐ์ฒด์˜ ์–‘๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„๋Š” ์–‘์ชฝ ๋ชจ๋‘ ๊ด€๊ณ„๋ฅผ ๋งบ์–ด์ฃผ์–ด์•ผ ์ˆœ์ˆ˜ํ•œ ๊ฐ์ฒด ์ƒํƒœ์—์„œ๋„ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

์ด๋ ‡๋“ฏ ์–‘๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„๋Š” ๊ฒฐ๊ตญ ์–‘์ชฝ ๋ชจ๋‘๋ฅผ ์‹ ๊ฒฝ์จ์•ผํ•œ๋‹ค. ๋งŒ์•ฝ, setTeam๊ณผ getMembers().add๋ฅผ ๊ฐ๊ฐ ํ˜ธ์ถœํ•˜๋ฉด ์‹ค์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ์–‘์ชฝ ๋ชจ๋‘์˜ ๊ด€๊ณ„๋ฅผ ๋งบ์–ด์ฃผ๋Š” ๊ฒƒ์„ ํ•˜๋‚˜์˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•˜๋‹ค.

public void setTeam(Team team) {
    this.team = team;
    team.getMembers().add(this);
}

์œ„์™€ ๊ฐ™์ด ํ•œ๋ฒˆ์— ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์—ฐ๊ด€๊ด€๊ณ„ ํŽธ์˜ ๋ฉ”์„œ๋“œ๋ผ๊ณ  ํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ์œ„์™€๊ฐ™์ด setTeam ๋ฉ”์„œ๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝ์šฐ ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋กœ

member1.setTeam(team1);
member1.setTeam(team2);

์œ„์™€ ๊ฐ™์ด ์—ฐ์†์ ์œผ๋กœ setTeam์„ ํ˜ธ์ถœํ•œ ์ดํ›„ team1์—์„œ ๋ฉค๋ฒ„๋ฅผ ์กฐํšŒํ•˜๋ฉด member1๊ฐ€ ์—ฌ์ „ํžˆ ์กฐํšŒ๋œ๋‹ค. team2๋กœ ๋ณ€๊ฒฝํ•  ๋•Œ team1๊ณผ์˜ ๊ด€๊ณ„๋ฅผ ์ œ๊ฑฐํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

--> ์ˆ˜์ •

public void setTeam(Team team) {
    if (this.team != null) { // ๊ธฐ์กด์— ์ด๋ฏธ ํŒ€์ด ์กด์žฌํ•œ๋‹ค๋ฉด
        this.team.getMembers().remove(this); // ๊ด€๊ณ„๋ฅผ ๋Š๋Š”๋‹ค.
    }
    this.team = team;
    team.getMembers().add(this);
}
taem1.addMember(member1);

// Team
public void addMember(Member member) {
    this.members.add(member);
    member.setTeam(this);
}

# 0603 - @DirtiesContext

์Šคํ”„๋ง ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ง„ํ–‰์‹œ ํ•˜๋‚˜์˜ Spring Context๋ฅผ ์žฌ์‚ฌ์šฉํ•จ์— ๋”ฐ๋ผ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.

@DirtiesContext ์–ด๋…ธํ…Œ์ด์…˜์€ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ ์ „, ์ˆ˜ํ–‰ ํ›„, ๊ฐ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋งˆ๋‹ค ์ˆ˜ํ–‰ํ•˜๊ธฐ ์ „ ์ˆ˜ํ–‰ํ•œ ์ดํ›„์— Context๋ฅผ ์žฌ์ƒ์„ฑํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

@DirtiesContext indicates that the underlying Spring ApplicationContext has been dirtied during the execution of a test (that is, the test modified or corrupted it in some mannerโ€‰โ€”โ€‰for example, by changing the state of a singleton bean) and should be closed. When an application context is marked as dirty, it is removed from the testing frameworkโ€™s cache and closed. As a consequence, the underlying Spring container is rebuilt for any subsequent test that requires a context with the same configuration metadata.
You can use @DirtiesContext as both a class-level and a method-level annotation within the same class or class hierarchy. In such scenarios, the ApplicationContext is marked as dirty before or after any such annotated method as well as before or after the current test class, depending on the configured methodMode and classMode.

doc.spring.io์— ๋”ฐ๋ฅด๋ฉด @DiritiesContext ApplicationContext ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋Š”๋™์•ˆ ํ…Œ์ŠคํŠธํ”„๋ ˆ์ž„์›Œํฌ์˜ ์บ์‹œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ๋‹ซ๊ฒŒํ•œ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ๊ธฐ๋ณธ Spring Container์— ๋™์ผํ•œ ๊ตฌ์„ฑ ๋ฉงํƒ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ํ•„์š”๋กœํ•˜๋Š” ํ›„์† ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ์žฌ ๋นŒ๋“œ๋œ๋‹ค๊ณ  ๋‚˜์™€์žˆ๋‹ค.

๋ฉ”์†Œ๋“œ๋‚˜ ํด๋ž˜์Šค๋ ˆ๋ฒจ์— ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์ด๋Š” ๊ฒƒ์œผ๋กœ ๋™์ž‘ํ•˜๋ฉฐ, methodMode, classMode์— ๋”ฐ๋ผ ๊ฐ๊ฐ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•˜๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. ํด๋ž˜์Šค์˜ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— context ์žฌ์ƒ์„ฑ
@DirtiesContext(classMode = BEFORE_CLASS)
public class FreshContextTests {
 // ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋“ค์ด ์ƒˆ๋กœ์šด context์—์„œ ์‹คํ–‰๋จ
}
  1. ํด๋ž˜์Šค์˜ ํ…Œ์ŠคํŠธ๊ฐ€ ๋ชจ๋‘ ๋๋‚œ ๋‹ค์Œ context ์žฌ์ƒ์„ฑ (๊ธฐ๋ณธ๊ฐ’)
@DirtiesContext
public class ContextDirtyingTests {
 // ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ context์˜ @Bean์˜ ์ƒํƒœ์— ์˜ํ–ฅ์„ ๋ผ์นจ
}
  1. ํด๋ž˜์Šค์˜ ๋ชจ๋“  ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋งˆ๋‹ค ์‹œ์ž‘ํ•˜๊ธฐ ์ด์ „์— context ์žฌ์ƒ์„ฑ
@DirtiesContex(classMode = BEFORE_EACH_TEST_METHOD)
public class FreshContextTests {
 // ๋ชจ๋“  ์ผ€์ด์Šค์—์„œ ์ƒˆ๋กœ์šด context๊ฐ€ ํ•„์š”ํ•จ
}
  1. ํด๋ž˜์Šค์˜ ๋ชจ๋“  ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ๋๋‚  ๋•Œ ๋งˆ๋‹ค context ์žฌ์ƒ์„ฑ
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)
public class ContextDirtyingTests {
 // ๋ชจ๋“  ์ผ€์ด์Šค๊ฐ€ context์˜ ์ƒํƒœ์— ์˜ํ–ฅ์„ ๋ผ์นจ
}
  1. ํŠน์ • ์ผ€์ด์Šค๋ฅผ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— context ์žฌ์ƒ์„ฑ
@DirtiesContext(methodMode = BEFORE_METHOD)
@Test
public void testProcessWhichRequiresFreshAppCtx() {
 // ์ƒˆ๋กœ์šด context๊ฐ€ ํ•„์š”ํ•œ ์–ด๋–ค ๋กœ์ง
}
  1. ํŠน์ • ์ผ€์ด์Šค๋ฅผ ์‹œ์ž‘ํ•œ ์ดํ›„ context ์žฌ์ƒ์„ฑ
@DirtiesContext
@Test
public void testProcessWhichDirtiesAppCtx() {
 // context์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์–ด๋–ค ๋กœ์ง
}

# 0605 - requireNonNull

์ž๋ฐ” 7์— ์ถ”๊ฐ€๋œ Objects ํด๋ ˆ์Šค์—์„œ ์ œ๊ณตํ•˜๋Š” Null ์ฒดํฌ๋ฅผ ์œ„ํ•œ ๋ฉ”์†Œ๋“œ ์ด๋‹ค. ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ž…๋ ฅ๋œ ๊ฐ’์ด null ์ด๋ผ๋ฉด NPE(NullPointerException)๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด ์ž…๋ ฅ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ„๋‹จํ•œ ๋ฉ”์†Œ์ด์ด๋‹ค. requireNonNull์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์„ธ๊ฐ€์ง€๋กœ ์˜ค๋ฒ„๋กœ๋”ฉ ๋˜์–ด์žˆ๋‹ค.

๋ฆฌํ„ดํƒ€์ž… ๋ฉ”์†Œ๋“œ
T requireNonNull(T obj)
T requireNonNull(T obj, String message)
T requireNonNull(T obj, Supplier msgSupplier)

์ฒซ๋ฒˆ์งธ ๋ฉ”์†Œ๋“œ๋Š” null์„ ์ „๋‹ฌํ•˜๋ฉด ๋ฉ”์„ธ์ง€๊ฐ€ ๋น„์–ด์žˆ๋Š” NPE ์˜ˆ์™ธ๋ฅผ ๋˜์ง„๋‹ค,

Objects.requireNonNull(null);
// java.lang.NullPointerException

๋‘๋ฒˆ์จฐ ๋ฉ”์†Œ๋“œ๋Š” null์„ ์ „๋‹ฌํ•˜๋ฉด, ๋‘๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•œ ๋ฌธ์ž์—ด์„ ๋ฉ”์„ธ์ง€๋กœ ๊ฐ–๋Š” NPE ์˜ˆ์™ธ๋ฅผ ๋˜์ง„๋‹ค.

Objects.requireNonNull(null, "null์€ ์ „๋‹ฌ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค!");
// java.lang.NullPointerException: null์€ ์ „๋‹ฌ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค!

์„ธ๋ฒˆ์งธ ๋ฉ”์†Œ๋“œ๋Š” null์„ ์ „๋‹ฌํ•˜๋ฉด, ๋‘๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•œ Supplier๋ฅผ ๊ตฌํ˜„ํ•œ ์ต๋ช… ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’์„ ๋ฉ”์„ธ์ง€๋กœ ๊ฐ–๋Š” NPE ์˜ˆ์™ธ๋ฅผ ๋˜์ง„๋‹ค.

Objects.requireNonNull(null, () -> "null์€ ์ „๋‹ฌ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค!");
// java.lang.NullPointerException: null์€ ์ „๋‹ฌ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค!

# requireNonNull์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

  • ๋น ๋ฅธ ์‹คํŒจ (Fail-Fast)
    ๋””๋ฒ„๊น…์„ ์‰ฝ๊ฒŒํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ ์ฆ‰๊ฐ์ ์œผ๋กœ ๊ฐ์ง€ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค. ๋ฌธ์ œ์˜ ์›์ธ๊ณผ ๋ฌธ์ œ์˜ ๋ฐœ์ƒ ์ง€์ ์ด ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๋–จ์–ด์ ธ ์žˆ๋‹ค๋ฉด ๋””๋ฒ„๊น…ํ•˜๊ธฐ ์–ด๋ ต๋‹ค.
  • ๋ช…์‹œ์„ฑ๊ณผ ๊ฐ€๋…์„ฑ
Last update: September 13, 2022 21:44
Contributors: ahnjs