๐Ÿš€ ์šฐ์•„ํ•œํ…Œํฌ์ฝ”์Šค 6๊ธฐ ํ”„๋ฆฌ์ฝ”์Šค - 2์ฃผ์ฐจ : ์ž๋™์ฐจ ๊ฒฝ์ฃผ

์ดํ•˜์–€ยท2023๋…„ 10์›” 28์ผ
0

โญ๏ธ troubleshooting

0๏ธโƒฃ ๊ธฐ์กด์˜ ํŒจํ‚ค์ง€ ๊ตฌ์กฐ

์„ค๋ช…์— ์•ž์„œ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…์ด ๋ฐœ์ƒํ–ˆ๋˜ ๊ธฐ์กด ํŒจํ‚ค์ง€ ๊ตฌ์กฐ๋ฅผ ์ฒจ๋ถ€ํ•ฉ๋‹ˆ๋‹ค!

...
โ””โ”€โ”€  src
     โ””โ”€โ”€ main/java/racingcar
         โ”œโ”€โ”€ Controller
         |	 โ””โ”€โ”€ RacingcargameController.java        
         |
         โ”œโ”€โ”€ Domain
         |	 โ”œโ”€โ”€ Car.java
         |   โ”œโ”€โ”€ Cars.java
         |   โ”œโ”€โ”€ Game.java
         |   โ””โ”€โ”€ Race.java
         |
         โ”œโ”€โ”€ Exception
         |   โ”œโ”€โ”€ CarNameException.java
         |   โ””โ”€โ”€ TryCountNumberException.java
         |
         โ”œโ”€โ”€ Service
         |   โ””โ”€โ”€ GameFlowManagementService.java
         |
         โ”œโ”€โ”€ Util
         |   โ””โ”€โ”€ ComputerNumberGenerator.java
         |
         โ”œโ”€โ”€ View
         |   โ”œโ”€โ”€ InputView.java
         |   โ””โ”€โ”€ OutputView.java
         |
         โ””โ”€โ”€ Application.java

1๏ธโƒฃ ์ฝ”๋“œ ์‹คํ–‰ ๋กœ์ง ์˜ค๋ฅ˜ ๋ฐœ์ƒ

ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ์ž๋™์ฐจ ์ด๋ฆ„๊ณผ ์‹œ๋„ ํšŸ์ˆ˜๋ฅผ ์ž…๋ ฅํ•˜๋ฉด
๊ฐ ์ฐจ์ˆ˜๋ณ„๋กœ "์‹คํ–‰๊ฒฐ๊ณผ"์™€ "์ตœ์ข… ์šฐ์Šน์ž : "๊ฐ€ ์ถœ๋ ฅ๋˜๋Š” ํ˜„์ƒ

์กฐ๊ฑด์— ์ฃผ์–ด์ง„ ์›๋ž˜์˜ ์ž…์ถœ๋ ฅ ์˜ˆ์‹œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ์ž๋™์ฐจ ์ด๋ฆ„๊ณผ ์‹œ๋„ ํšŸ์ˆ˜๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ๊ทธ์— ๋งž๊ฒŒ ๊ฒฝ์ฃผ๋ฅผ ๋ชจ๋‘ ์‹คํ–‰ํ•œ ํ›„, ๋ˆ„์ ๋œ ์šฐ์Šน์— ๋”ฐ๋ฅธ ์ตœ์ข… ์šฐ์Šน์ž๊ฐ€ ๋‚˜์™€์•ผํ•˜๋Š” ๋ฐฉ์‹์ด์ฃ ๐Ÿ†

๊ฒฝ์ฃผํ•  ์ž๋™์ฐจ ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š”.(์ด๋ฆ„์€ ์‰ผํ‘œ(,) ๊ธฐ์ค€์œผ๋กœ ๊ตฌ๋ถ„)
pobi,woni,jun
์‹œ๋„ํ•  ํšŒ์ˆ˜๋Š” ๋ช‡ํšŒ์ธ๊ฐ€์š”?
5

์‹คํ–‰ ๊ฒฐ๊ณผ
pobi : -
woni : 
jun : -

pobi : --
woni : -
jun : --

pobi : ---
woni : --
jun : ---

pobi : ----
woni : ---
jun : ----

pobi : -----
woni : ----
jun : -----

์ตœ์ข… ์šฐ์Šน์ž : pobi, jun

ํ•˜์ง€๋งŒ, ์ œ๊ฐ€ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ์˜ ํ˜„์žฌ์˜ ์ž…์ถœ๋ ฅ์€ ๊ฐ ์ฐจ์ˆ˜๋ณ„๋กœ ์‹คํ–‰๊ฒฐ๊ณผ์™€ ์ตœ์ข… ์šฐ์Šน์ž๊ฐ€ ๊ฐ๊ฐ ์ถœ๋ ฅ๋˜๋Š” ํ˜•ํƒœ๋กœ ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค๐Ÿ˜ญ

๊ฒฝ์ฃผํ•  ์ž๋™์ฐจ ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š”.(์ด๋ฆ„์€ ์‰ผํ‘œ(,) ๊ธฐ์ค€์œผ๋กœ ๊ตฌ๋ถ„)
pobi,woni,jun
์‹œ๋„ํ•  ํšŒ์ˆ˜๋Š” ๋ช‡ํšŒ์ธ๊ฐ€์š”?
5

์‹คํ–‰ ๊ฒฐ๊ณผ
pobi : ---
woni : ---
jun : ---

์ตœ์ข… ์šฐ์Šน์ž: pobi, woni, jun
์‹คํ–‰ ๊ฒฐ๊ณผ
pobi : ----
woni : --
jun : ---

์ตœ์ข… ์šฐ์Šน์ž: pobi
์‹คํ–‰ ๊ฒฐ๊ณผ
pobi : ---
woni : --
jun : --

์ตœ์ข… ์šฐ์Šน์ž: pobi
์‹คํ–‰ ๊ฒฐ๊ณผ
pobi : --
woni : ----
jun : ----

์ตœ์ข… ์šฐ์Šน์ž: woni, jun
์‹คํ–‰ ๊ฒฐ๊ณผ
pobi : ----
woni : --
jun : -

์ตœ์ข… ์šฐ์Šน์ž: pobi

๋”ฐ๋ผ์„œ, ์›์ธ์„ ์ฐพ๊ธฐ ์œ„ํ•ด Car.java ํŒŒ์ผ์˜ tryCount๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

Domain/Car.java

    public void playGame(int tryCount) {
        for (int i = 0; i < tryCount; i++) {
            playOneRound();
            List<Car> roundWinners = getWinners();
            roundWinners.addAll(roundWinners);
        }
        roundWinners.addAll(getWinners());
    }
  • ํ•ด๋‹น ๋ถ€๋ถ„์€ ์‹œ๋„ ํšŸ์ˆ˜๋ฅผ ์ž…๋ ฅ๋ฐ›์€ ๋งŒํผ, ๊ฒฝ์ฃผ๋ฅผ ๋ฐ˜๋ณตํ•˜๋Š” ๋กœ์ง์ž…๋‹ˆ๋‹ค.
    addAll์„ ์‚ฌ์šฉํ•ด ๊ฒŒ์ž„์˜ ์šฐ์Šน์ž๋ฅผ ๋ˆ„์ ํ•˜๊ณ  ์ตœ์ข… ์šฐ์Šน์ž๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์„ฑํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋กœ์ง ์ž์ฒด๋Š” ๋งž๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‘๋ฒˆ์งธ๋กœ, Race.java ํŒŒ์ผ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.
Domain/Race.java

    public static void start(List<String> carNames, int tryCount) {
        List<Car> cars = createCars(carNames);
        Game game = new Game(cars);
        game.playGame(tryCount);

        List<Car> winners = game.getWinners();
        OutputView.printHead();
        OutputView.printRaceResult(cars);
        OutputView.printWinners(winners);
    }
  • ์ด ๋ถ€๋ถ„์€ ์ฐจ์˜ ์ด๋ฆ„ ๊ทธ๋ฆฌ๊ณ  ์‹œ๋„ ํšŸ์ˆ˜๋ฅผ ๊ฐ€์ ธ์™€ ๊ฒฝ์ฃผ๋ฅผ ์ง„ํ–‰ํ•œ ๋งŒํผ ๋ˆ„์ ๋œ ์šฐ์Šน์ž๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ๊ทธ์— ๋”ฐ๋ผ printHead์ธ "์‹คํ–‰๊ฒฐ๊ณผ"๋ฅผ ์ถœ๋ ฅํ•˜๊ณ , ์‹ค์ œ๋กœ ์‹คํ–‰๋œ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ฃผ๋ฉฐ ์ตœ์ข… ์šฐ์Šน์ž๊นŒ์ง€ ๋ณด์—ฌ์ฃผ๋Š” ๋กœ์ง์ž…๋‹ˆ๋‹ค.
    ์ด ์—ญ์‹œ ๋กœ์ง์—์„œ์˜ ํฐ ๋ฌธ์ œ์ ์€ ๋ฐœ๊ฒฌํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.
    (์ œ๊ฐ€ ํŒŒ์•…ํ•˜์ง€ ๋ชปํ•œ ์–ด๋”˜๊ฐ€์—์„œ ์ƒ๊ธด ๋ฌธ์ œ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค...๐Ÿ’ฆ)

2๏ธโƒฃ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ฐ€ ์•ˆ๋œ๋‹ค...?

IllegalArgumentException์ด ๋ฐœ์ƒ๋˜์–ด์•ผ ํ•˜์ง€๋งŒ
-> CarNameException์˜ ๊ฒฝ์šฐ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ฐ€ ์•„์˜ˆ ๋ฐœ์ƒ๋˜์ง€ ์•Š๋Š”๋‹ค.
->TryCountException์˜ ๊ฒฝ์šฐ NumberFormatException์ด ๋ฐœ์ƒํ•œ๋‹ค.

ํ•œ๊ฐ€์ง€๋งŒ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋ฉด ์–ผ๋งˆ๋‚˜ ์ข‹์„๊นŒ์š”??
ํ•˜์ง€๋งŒ ๊ทธ๋Ÿด ์ˆ˜ ์—†์ฃ ๐Ÿ˜ฉ

์šฐ์„  ๋จผ์ € CarNameException.java๋ฅผ ๊ฐ€์ ธ์™€๋ณผ๊ฒŒ์š”.
Exception/CarNameException.java

package racingcar.Exception;

public class CarNameException extends IllegalArgumentException {
    public CarNameException() {
        super("์ž๋™์ฐจ ์ด๋ฆ„์€ 1์ž ์ด์ƒ, 5์ž ์ดํ•˜๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.");
    }

    public static void validateCarName(String name) {
        if (name == null || name.length() < 1 || name.length() > 5) {
            throw new CarNameException();
        }
    }
}

validateCarName์„ ํ†ตํ•ด ์ด๋ฆ„์˜ ๊ธธ์ด๊ฐ€ ๊ณต๋ฐฑ์ด๊ฑฐ๋‚˜, 1 ์ดํ•˜, 5 ์ด์ƒ์ผ ๋•Œ IllegalArgumentException์ด ๋ฐœ์ƒ๋˜๋„๋ก ๋กœ์ง์„ ๊ตฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์•„์˜ˆ ์˜ˆ์™ธ๋กœ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์•˜์–ด์š”๐Ÿ˜…

๋”ฐ๋ผ์„œ 3๊ฐ€์ง€๋ฅผ ํ•œ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๋„๋ก ์ด๋ ‡๊ฒŒ ์ˆ˜์ •ํ•ด๋ดค์ง€๋งŒ, ์—ฌ์ „ํžˆ ์ž‘๋™ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

public class CarValidator {
    public static void validateCarName(String name) {
        if (name == null) {
            throw new CarNameNullException();
        }
        if (name.length() < 1 || name.length() > 5) {
            throw new CarNameLengthException();
        }
    }
}

3๏ธโƒฃ ํ…Œ์ŠคํŠธ ํ†ต๊ณผ๊ฐ€ ๋˜์ง€ ์•Š์•„...๐Ÿ˜ญ

๊ธฐ๋ณธ์ ์œผ๋กœ ์ฃผ์–ด์ง„ ํ…Œ์ŠคํŠธ๋Š” 2๊ฐ€์ง€์ธ๋ฐ,
-> ์ „์ง„_์ •์ง€()์—์„œ test failed๊ฐ€ ๋ฐœ์ƒ!
-> ์‹ ๊ธฐํ•˜๊ฒŒ๋„ ๊ทธ ๋‹ค์Œ์˜ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋Š” ์ •์ƒ์ ์œผ๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ํ†ต๊ณผํ•œ๋‹ค? ๋ถ„๋ช… ์˜ˆ์™ธ๋กœ ์ฒ˜๋ฆฌ๊ฐ€ ์•ˆ๋˜๊ณ  ๊ฒฝ์ฃผ๊ฐ€ ์ง„ํ–‰๋˜์—ˆ๋Š”๋ฐ ๋ง์ด์ง€๐Ÿง

๊ธฐ๋ณธ ์ œ๊ณต๋œ ํ…Œ์ŠคํŠธ๋Š” ์ „์ง„ ์ •์ง€() ์™€ ์ด๋ฆ„์— ๋Œ€ํ•œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ() ์˜ ์ด 2๊ฐ€์ง€๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.
test/java/racingcar/ApplicationTest.java

@Test
    void ์ „์ง„_์ •์ง€() {
        assertRandomNumberInRangeTest(
            () -> {
                run("pobi,woni", "1");
                assertThat(output()).contains("pobi : -", "woni : ", "์ตœ์ข… ์šฐ์Šน์ž : pobi");
            },
            MOVING_FORWARD, STOP
        );
    }
@Test
    void ์ด๋ฆ„์—_๋Œ€ํ•œ_์˜ˆ์™ธ_์ฒ˜๋ฆฌ() {
        assertSimpleTest(() ->
                assertThatThrownBy(() -> runException("pobi,javaji", "1"))
                        .isInstanceOf(IllegalArgumentException.class)
        );
    }
  • ๊ฒฝ์ฃผ๋ฅผ ์œ„ํ•ด ์ž๋™์ฐจ๊ฐ€ ์ž˜ ์ „์ง„ํ•˜๋Š”์ง€์™€ ์ž๋™์ฐจ์˜ ์ด๋ฆ„ ์˜ˆ์™ธ๋ฅผ ์ž˜ ์ฒ˜๋ฆฌํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์ด๋ฉฐ, ์•„๋ฌด๋ž˜๋„ "์ „์ง„_์ •์ง€()"๋Š” ์œ„์˜ ์ž…์ถœ๋ ฅ ์˜ค๋ฅ˜๋กœ ์ธํ•ด ์ด ๋ถ€๋ถ„์˜ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

๐Ÿ“ฃ ํ•ด๊ฒฐ๋ถˆ๊ฐ€ ์„ ์–ธ

์ฝ”๋“œ ์žฌ๊ตฌ์„ฑ ๊ฒฐ์ •!! ๋•…๋•…๐Ÿ‘ฉ๐Ÿปโ€โš–๏ธ

๊ฒฐ๊ตญ, ์ฝ”๋“œ๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ์งœ๋Š” ๊ฒƒ์œผ๋กœ ํ•ด๊ฒฐ์ ์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค!
๋ญ ํ•ญ์ƒ ๋‹ค๋“ค ๊ทธ๋ ‡์ง€ ์•Š๋‚˜์š”...?? ํ•˜ํ•˜ํ•˜ํ•˜๐Ÿคฆ๐Ÿปโ€โ™€๏ธ

ํŒจํ‚ค์ง€ ๊ตฌ์กฐ๋Š” ์–ด๋Š์ •๋„ ์œ ์ง€ํ•˜๋˜, ์•„๋ฌด๋ž˜๋„ ์ฐจ์˜ ์ด๋ฆ„์˜ ์˜ˆ์™ธ๋„ ์ž˜ ์žก์ง€ ๋ชปํ•˜๊ณ  ์ „์ง„ ์ •์ง€๋„ ์ž˜ ์žก์ง€ ๋ชปํ•˜๋‹ˆ Repository ๊ฐœ๋…์„ ์ด์šฉํ•ด ํŒจํ‚ค์ง€์— ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.


Repository? ๊ทธ๊ฑฐ DB์žˆ์„๋•Œ๋งŒ ์“ฐ๋Š”๊ฑฐ ์•„๋ƒ?

  • Spring์„ ์ž์ฃผ ์‚ฌ์šฉํ•˜์‹  ๋ถ„๋“ค์—๊ฒŒ ์กฐ๊ธˆ ๋” ์ต์ˆ™ํ•œ ํŒจํ‚ค์ง€ ์ด๋ฆ„์ผ ์ˆ˜๋„ ์žˆ์–ด์š”!
    ์ € ์—ญ์‹œ๋„ ๋งค์šฐ ์ต์ˆ™ํ•ฉ๋‹ˆ๋‹ค๐Ÿ˜€
    ๋Œ€๋ถ€๋ถ„ DB์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ ์ฝ”๋“œ๋ฅผ ์ด๊ณณ์— ์ž‘์„ฑํ•˜์ฃ ?

  • ํ•˜์ง€๋งŒ, ์ œ๊ฐ€ ์‚ฌ์šฉํ•˜๋ ค๋Š” Repository ํŒจํ‚ค์ง€ ์‚ฌ์šฉ ๋ชฉ์ ์€ ๋น„์Šทํ•˜๋ฉด์„œ๋„ ์กฐ๊ธˆ์€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.
    ์‹ค์ œ๋กœ DB์— ์ €์žฅํ•˜์ง€๋Š” ์•Š์ง€๋งŒ, ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ๋กœ ๊ฐ’์„ ์ €์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— DB์™€ ๋น„์Šทํ•œ ์—ญํ• ์„ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

    1. ๊ฒŒ์ž„์„ ์‹œ์ž‘ํ•˜๋ฉด ์ž๋™์ฐจ์˜ ์ด๋ฆ„์„ ๋ฐ›์•„์„œ ์ €์žฅํ•˜๊ณ  ์žˆ์–ด์•ผ ํ•˜๊ณ 
    2. ์‹œ๋„ ํšŸ์ˆ˜๋„ ์ €์žฅํ•˜๊ณ  ์žˆ์–ด์•ผ ํ•˜๋‹ˆ๊นŒ์š”.
  • ์ด๋ ‡๊ฒŒ ๋œ๋‹ค๋ฉด

    1. ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅ ์‹œ์— ๊ฐ™์€ ์ด๋ฆ„์˜ ์ž๋™์ฐจ๋ฅผ ๋“ฑ๋กํ•˜๋ ค ํ•˜๋Š” ๊ฒƒ์„ ๋ง‰์„ ์ˆ˜ ์žˆ๊ณ 
    2. ์ด๋ฆ„์˜ ์ œํ•œ ๊ธ€์ž ์ˆ˜๋„ ์ •ํ™•ํ•˜๊ฒŒ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ
    3. ์‹œ๋„ ํšŸ์ˆ˜๋ฅผ ํ†ตํ•ด ๊ฒŒ์ž„์˜ ์ข…๋ฃŒ์™€ ์ตœ์ข… ์šฐ์Šน์ž๋ฅผ ๋ฝ‘์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
  • ๋งˆ์ง€๋ง‰์œผ๋กœ, ์ž๋™์ฐจ์˜ ์ด๋ฆ„ ์ •๋ณด๋ฅผ ๋ฌธ์ž์—ด ์ž์ฒด๋กœ ๊ธฐ์–ตํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์ง€๋งŒ ๊ฐœ์ธ์ ์œผ๋กœ๋Š” ๊ณ ์œ ์˜ ID๊ฐ’์ด ์žˆ๋‹ค๋ฉด ์ฒ˜๋ฆฌ๊ฐ€ ์กฐ๊ธˆ ๋” ์šฉ์ดํ•˜์ง€ ์•Š์„๊นŒ?ํ•˜๋Š” ๊ณ ๋ฏผ๋„ ์žˆ์–ด์„œ ๊ฒฐ์ •ํ–ˆ๋‹ต๋‹ˆ๋‹ค๐Ÿ˜Ž

    ๋ฒˆ์™ธ๋กœ ๋””๋ ‰ํ„ฐ๋ฆฌ ๊ตฌ์กฐ๊ฐ€ ๊ถ๊ธˆํ•˜์‹  ๋ถ„๋“ค์€ ๐Ÿ“Spring Guide - Directory
    ํŒจํ‚ค์ง€ ๊ตฌ์กฐ ๊ฐ€์ด๋“œ
    ๋ฅผ ์ฐธ๊ณ ํ•˜์‹œ๋ฉด ๊ธฐ๋ณธ์ ์ธ ํ˜•ํƒœ๋ฅผ ์•Œ์•„๋ณด์‹ค ์ˆ˜ ์žˆ์–ด์š”!


๋˜ํ•œ, Controller์™€ Servic ์—ญ์‹œ ์ด์ „์˜ 1์ฃผ์ฐจ ์˜จ๋ณด๋”ฉ ๋ฏธ์…˜์ด์—ˆ๋˜ ์ˆซ์ž ์•ผ๊ตฌ ๊ฒŒ์ž„์˜ ์‚ฌ์šฉ์„ฑ๊ณผ ๋™์ผํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค Countroller๊ฐ€ ์ฝ”๋“œ์˜ ๋ชจ๋“  ๊ด€๋ฆฌ๋ฅผ ํ•˜๊ณ  ์ง‘ํ•ฉ ์ €์žฅ์†Œ๊ฐ€ ๋˜๋Š” ๊ฒƒ์ด ์˜์กด๋„๊ฐ€ ๊ณผํ•˜๊ฒŒ ๋†’์•„์ง€๋Š” ๊ฒƒ ๊ฐ™์•„ ์ปจํŠธ๋กค๋Ÿฌ์˜ ์ฑ…์ž„์„ ๋ถ„์‚ฐํ•˜๋ ค๋Š” ๋ชฉ์ ์œผ๋กœ, Service ์—ญ์‹œ View์™€์˜ ์˜์กด๋„๊ฐ€ ๋†’์•„ ๋ถ„์‚ฐํ•˜๋Š” ๊ฒƒ์„ ๋ชฉ์ ์œผ๋กœ ์—ญํ• ์„ ๋‹ค๋ฅด๊ฒŒ ์„ค์ •ํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค.

Domain๋„ ํŒŒ์ผ ์ž์ฒด๋ฅผ ์—ญํ• ์— ๋”ฐ๋ผ์„œ 4๊ฐ€์ง€๋กœ ๋ถ„์‚ฐํ–ˆ์œผ๋‚˜ ์˜คํžˆ๋ ค ์˜ค๋ฅ˜๊ฐ€ ๋ฒˆ์ง€๋Š” ์›์ธ์ด ๋˜๋Š” ๊ฒƒ์œผ๋กœ ์ƒ๊ฐํ•˜๊ฒŒ ๋˜์–ด ์ด์ „์˜ ๋ฐฉ์‹์„ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์–ด๋–จ๊นŒ ๊ณ ๋ฏผํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋„ˆ๋ฌด ๋งŽ์€ ์‹œ๊ฐ„์„ ๋ณด๋‚ด๊ณ  ์žˆ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์–ด ์ด๋ฒˆ ๋ฏธ์…˜์—์„œ๋„ ์ด์ „์˜ 1์ฃผ์ฐจ ๋ฏธ์…˜์—์„œ์™€ ๊ฐ™์€ ๋ชฉ์ ์„ ๊ฐ€์ง„ ํŒจํ‚ค์ง€๋กœ ๊ตฌ์„ฑํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค๐Ÿคฏ

๋ณ€๊ฒฝ๋œ ํŒจํ‚ค์ง€ ๊ตฌ์กฐ

...
โ””โ”€โ”€  src
     โ””โ”€โ”€ main/java/racingcar
         โ”œโ”€โ”€ Controller
         |	 โ””โ”€โ”€ RacingcargameController.java        
         |
         โ”œโ”€โ”€ Domain
         |	 โ”œโ”€โ”€ Car.java
         |   โ””โ”€โ”€ Game.java
         |
         โ”œโ”€โ”€ Repository
         |	 โ”œโ”€โ”€ CarRepository.java
         |   โ””โ”€โ”€ GameRepository.java
         |
         โ”œโ”€โ”€ Exception
         |   โ”œโ”€โ”€ CarNameException.java
         |   โ””โ”€โ”€ TryCountNumberException.java
         |
         โ”œโ”€โ”€ Service
         |   โ””โ”€โ”€ GameFlowManagementService.java
         |
         โ”œโ”€โ”€ Util
         |   โ”œโ”€โ”€ ComputerNumberGenerator.java
         |   โ””โ”€โ”€ StringToList.java
         |
         โ”œโ”€โ”€ View
         |   โ”œโ”€โ”€ InputView.java
         |   โ””โ”€โ”€ OutputView.java
         |
         โ””โ”€โ”€ Application.java

โญ๏ธTest๋ฅผ ํ†ตํ•ด ์˜ˆ์™ธ ์ ์šฉ ์ œ๋Œ€๋กœ ํ•˜๊ธฐ!

CarNameException ํ…Œ์ŠคํŠธ

๊ธฐ์กด์˜ CarNameException ์ผ๋ถ€

Exception/CarNameException.java

...
public class CarNameException {
    private final StringToList stringToList = new StringToList();
    private static final int MINIMUM_CARNAME_LENGTH = 1;
    private static final int MAXIMUM_CARNAME_LENGTH = 5;
    private static final String BLANK = "";


    public void validateCarNameInput(String carNameInput) throws IllegalArgumentException {
        List<String> carNameList = stringToList.analysisCarNames(carNameInput);
        checkCarNameIsOutOfRangeAndBlank(carNameList);
        checkCarNameIsDuplication(carNameList);
        
        checkInputIsEmpty(carNameInput);
        checkLastInputIsComma(carNameInput);
    }
...

์—ฌ๊ธฐ์—์„œ, validateCarNameInput์˜ ์ˆœ์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ
  • ๋ฒ”์œ„ ์ดˆ๊ณผ ๋ฐ ๊ณต๋ฐฑ
  • ์ค‘๋ณต

๋˜ํ•œ, ๊ณต๋ฐฑ๊ณผ ์‰ผํ‘œ ์—ญ์‹œ ๋ฉ”์„œ๋“œ๋ฅผ ๋ถ„๋ฆฌํ•ด ํ•จ๊ป˜ ๋„ฃ์–ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

์ด ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด Application์„ ๊ตฌ๋™ํ•˜๋ฉด, ์ •์ƒ์ ์œผ๋กœ ์˜ˆ์™ธ๋ฅผ ์ถœ๋ ฅํ•  ๊ฒƒ์ด๋ผ ์ƒ๊ฐํ•˜๊ณ  ๋ฌธ์ œ์ ์„ ํŒŒ์•…ํ•˜์ง€ ๋ชปํ•˜๊ณ  ์žˆ๋Š” ์ƒํƒœ์˜€์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋‹ค์Œ์˜ ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ๋•Œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ํŒŒ์ผ ์ „๋ฌธ์„ ์ฒจ๋ถ€ํ• ๊ฒŒ์š”!
Test/java/racingcar/Exception/CarNameExceptionTest.java

package racingcar.Exception;

import org.junit.jupiter.api.Test;
import racingcar.Exception.CarNameException;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;

public class CarNameExceptionTest {

    @Test
    void testValidateCarNameInput_ValidInput_์˜ฌ๋ฐ”๋ฅธ_์ž…๋ ฅ() {
        // given
        CarNameException carNameException = new CarNameException();
        String carNameInput = "a,b,c";

        // when, then
        assertDoesNotThrow(() -> carNameException.validateCarNameInput(carNameInput));
    }
    @Test
    void testValidateCarNameInput_NoInput_์ž…๋ ฅ๊ฐ’_์—†์Œ() {
        // given
        CarNameException carNameException = aCarNameException();
        String carNameInput = "";

        // when, then
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
                () -> carNameException.validateCarNameInput(carNameInput));
        assertThat(exception.getMessage()).isEqualTo("๊ฐ’์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.");
    }

    @Test
    void testValidateCarNameInput_LastInputComma_์ž…๋ ฅ๊ฐ’_๋_์‰ผํ‘œ() {
        // given
        CarNameException carNameException = aCarNameException();
        String carNameInput = "a,b,c,";

        // when, then
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
                () -> carNameException.validateCarNameInput(carNameInput));
        assertThat(exception.getMessage()).isEqualTo("์ž๋™์ฐจ ์ด๋ฆ„์€ 1๊ธ€์ž ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.");
    }

    @Test
    void testValidateCarNameInput_InvalidLength_๊ธธ์ด_๋ฏธ๋งŒ() {
        // given
        CarNameException carNameException = aCarNameException();
        String carNameInput = ",b,c";

        // when, then
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
                () -> carNameException.validateCarNameInput(carNameInput));
        assertThat(exception.getMessage()).isEqualTo("์ž๋™์ฐจ ์ด๋ฆ„์€ 1๊ธ€์ž ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.");
    }

    @Test
    void testValidateCarNameInput_InvalidLength_๊ธธ์ด_์ดˆ๊ณผ() {
        // given
        CarNameException carNameException = new CarNameException();
        String carNameInput = "a,bcdefgh,b";

        // when, then
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
                () -> carNameException.validateCarNameInput(carNameInput));
        assertThat(exception.getMessage()).isEqualTo("์ž๋™์ฐจ ์ด๋ฆ„์€ 5๊ธ€์ž ์ดํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.");
    }

    @Test
    void testValidateCarNameInput_CarNameWithSpace_๊ณต๋ฐฑ์ด_ํฌํ•จ๋œ_์ด๋ฆ„() {
        // given
        CarNameException carNameException = new CarNameException();
        String carNameInput = "a a,b,c";

        // when, then
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
                () -> carNameException.validateCarNameInput(carNameInput));
        assertThat(exception.getMessage()).isEqualTo("์ž๋™์ฐจ ์ด๋ฆ„์•ˆ์—๋Š” ๊ณต๋ฐฑ์ด ์žˆ์–ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค.");
    }


    @Test
    void testValidateCarNameInput_DuplicateCarName_์ค‘๋ณต๋œ_์ด๋ฆ„() {
        // given
        CarNameException carNameException = new CarNameException();
        String carNameInput = "a,a,b";

        // when, then
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
                () -> carNameException.validateCarNameInput(carNameInput));
        assertThat(exception.getMessage()).isEqualTo("๊ฐ™์€ ์ด๋ฆ„์„ ๊ฐ€์ง„ ์ž๋™์ฐจ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.");
    }


    private CarNameException aCarNameException() {
        return new CarNameException();
    }
}


์š”๋ ‡๊ฒŒ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฐ๋ฐ ์—ฌ๊ธฐ์—์„œ ์ด์ƒํ•œ ์ ์„ ๋ฐœ๊ฒฌํ–ˆ์–ด์š”.
ApplicationTest์˜ ์ „์ง„_์ •์ง€() ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๊ฒ๋‹ˆ๋‹ค!

์˜ค๋ฅ˜๋ฅผ ๋‹ค์‹œ ๋ณด์ž๐Ÿง

๋‹จ์ˆœํžˆ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ์˜ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์ง€๋งŒ ์•Œ๊ณ ๋ณด๋‹ˆ CarNameException ์ฝ”๋“œ ์ž์ฒด์˜ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ์–ด์š”:)

๋‹ค์‹œ ํ•œ๋ฒˆ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!
Exception/CarNameException.java

...
public class CarNameException {
    private final StringToList stringToList = new StringToList();
    private static final int MINIMUM_CARNAME_LENGTH = 1;
    private static final int MAXIMUM_CARNAME_LENGTH = 5;
    private static final String BLANK = " ";
...
  • String BLANK์—์„œ ๊ณต๋ฐฑ์„ ์žก์œผ๋ ค๋ฉด ""๊ฐ€ ์•„๋‹Œ -> " "๊ฐ€ ๋˜์–ด์•ผ ๊ฒ ์ฃ ?
    "๊ณผ "์˜ ์‚ฌ์ด์— space ๊ณต๋ฐฑ์ด ํ•„์š”ํ•œ๋ฐ, ์ด ๋ถ€๋ถ„์„ ์ ์šฉํ•˜์ง€ ์•Š์•„ Application์„ ์‹คํ–‰ํ–ˆ์„ ๋•Œ ๋งž๋Š” ์ด๋ฆ„์„ ๋„ฃ์—ˆ์Œ์—๋„ fail ๋˜์—ˆ์—ˆ์Šต๋‹ˆ๋‹ค!



public void validateCarNameInput(String carNameInput) throws IllegalArgumentException {
        checkInputIsEmpty(carNameInput);
        checkLastInputIsComma(carNameInput);
        List<String> carNameList = stringToList.analysisCarNames(carNameInput);
        checkCarNameIsOutOfRangeAndBlank(carNameList);
        checkCarNameIsDuplication(carNameList);
    }
  • ์ด ๊ณณ์˜ ์ˆœ์„œ์— ์ฃผ๋ชฉํ•ด์ฃผ์„ธ์š”!
    ์ž˜ ๋ณด๋ฉด, ๊ณต๋ฐฑ๊ณผ ์ฝค๋งˆ ์ฒ˜๋ฆฌ๋ฅผ ๋จผ์ € ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์ฃ ?

java๋Š” ์ฝ”๋“œ์˜ ์œ—๋ถ€๋ถ„๋ถ€ํ„ฐ ์ฐจ๋ก€๋Œ€๋กœ ์ฒ˜๋ฆฌํ•ด ๋‚˜๊ฐ€๋Š” ํŠน์„ฑ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์šฐ์„ ์ ์œผ๋กœ ์ž‘์„ฑ๋œ ์ฝ”๋“œ๊ฐ€ ์šฐ์„ ๊ถŒ์„ ๊ฐ€์ง„๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ์ข‹์•„์š”!

๊ทธ๋Ÿผ, ๋‹ค์‹œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

-> ์„ฑ๊ณต์ž…๋‹ˆ๋‹ค๐Ÿ˜†

profile
์–ธ์  ๊ฐ€ ๋‚ด ์ฝ”๋“œ๋กœ ์„ธ์ƒ์— ๊ธฐ์—ฌํ•  ์ˆ˜ ์žˆ๋„๋ก, BE&Data Science ๊ฐœ๋ฐœ ๊ธฐ๋ก ๋…ธํŠธโ˜˜๏ธ

0๊ฐœ์˜ ๋Œ“๊ธ€