JUnit, Test ๋ฝ€๊ฐœ๊ธฐ ๐Ÿ‘Š

์˜ค์˜์„ ยท2023๋…„ 11์›” 9์ผ
0

@MethodSource() ๐Ÿ‘Š

@ParameterizedTestย - @MethodSource

@ValueSource(), @CsvSource() ๋ฅผ ํ†ตํ•ด ๊ธฐ๋ณธ ints, strings ๋“ฑ ๋‹ค์–‘ํ•œ ์ž๋ฐ”์˜ ํƒ€์ž…์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด ๋„˜๊ฒจ์ฃผ๊ณ , ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ธ์ž๋ฅผ csvํ˜•์‹์œผ๋กœ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ์—ˆ๋‹ค!

๊ทธ๋Ÿฐ๋ฐ ์ข€ ๋” โ€œ๋ณต์žกํ•œโ€ ๋…€์„๋“ค์„ ๋„˜๊ฒจ์ฃผ๊ณ  ์‹ถ๋‹ค๋ฉด? ๐Ÿคจ

์˜ˆ๋ฅผ ๋“ค์–ด List ๊ฐ์ฒด, ๋˜๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ๊ฐ์ฒด ๊ฐ™์€ ๋…€์„๋“ค ๋ง์ด๋‹ค!

*@MethodSouce : ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ •์˜ํ•˜๊ณ , ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š” method๋ฅผ ์ •์˜ํ•˜์ž. ๊ทธ๋ฆฌ๊ณ  Stream์„ ๋ฐ˜ํ™˜๋ฐ›์ž! (static)*

์‚ฌ์šฉ ์˜ˆ์‹œ์™€ ํ•จ๊ป˜ ๋ณด๋ฉด ๋” ๋น ๋ฅด๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.

@ParameterizedTest
@MethodSource("generateTestLottoInput")
void ๋กœ๋˜๋ฒˆํ˜ธ๋ฅผ_๋ฐ›๋Š”๋‹ค(List<Integer> input) {
     System.out.println(input);
}
	
static Stream<List<Integer>> **generateTestLottoInput**() {
        return Stream.of(
                List.of(8, 21, 23, 41, 42, 43),
                List.of(3, 5, 11, 16, 32, 38),
                List.of(7, 11, 16, 35, 36, 44)
        );
    }

@MethodSource("generateTestLottoInput")๋Š” generateTestLottoInput() ๋ฅผ ํ˜ธ์ถœํ•ด ์ธ์ž๋ฅผ ๋ฐ›์•„์˜ฌ ๊ฒƒ์ž„์„ ๋ช…์‹œํ•˜๊ณ  ์žˆ๋‹ค.

generateTestLottoInput() ๋Š” List<Integer>๋กœ ๊ตฌ์„ฑ๋œ Stream์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค!

๊ทธ๋ฆฌ๊ณ  Stream, List์™€ ๊ฐ™์€ ๊ฐ์ฒด๋Š” of() (static)ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ ๊ฐ€๋Šฅํ•˜๋‹ค.

์ž ๊น! ๊ทธ๋Ÿผ ๋ณต์žกํ•œ ๊ฐ์ฒด๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ ๋ฐ›๊ณ ์‹ถ๋‹ค๋ฉด์š”? CsvSource+Methodโ€ฆ?!

๋‹น์—ฐํžˆ ๊ทธ๋Ÿด ํ•„์š” ์—†์ด, ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ธ์ž๋ฅผ ๋ฐ›๊ณ  ์‹ถ์„๋•Œ๋Š” Arguments๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

Arguments๋ฅผ ์‚ฌ์šฉํ•ด ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ธ์ž๋ฅผ ํ•œ๋ฒˆ์— ๋ฌถ๊ณ , ์ด๋ฅผ Stream์œผ๋กœ ๊ตฌ์„ฑํ•ด ๋ฐ˜ํ™˜ํ•˜์ž!

@ParameterizedTest
@MethodSource("generateTestLottoInput")
void ๋กœ๋˜์™€_๊ตฌ์ž…๊ธˆ์•ก_์ธ์ž๋กœ๋ฐ›๊ธฐ(List<Integer> input, int money) {
    System.out.println(input);
    System.out.println(money);
}

static Stream<Arguments> **generateTestLottoInput**() {
    return Stream.of(
        Arguments.arguments(List.of(7, 11, 16, 35, 36, 44), 8000),
        Arguments.arguments(List.of(3, 5, 11, 16, 32, 38), 1000),
    );
}

NsTest ๐Ÿ‘Š

assertRandomNumberInRangeTest

    @Test
    void ๊ธฐ๋Šฅ_ํ…Œ์ŠคํŠธ() {
        assertRandomUniqueNumbersInRangeTest(
                () -> {
                    run("8000", "1,2,3,4,5,6", "7");
                    assertThat(output()).contains(
                            "8๊ฐœ๋ฅผ ๊ตฌ๋งคํ–ˆ์Šต๋‹ˆ๋‹ค.",
                            "[8, 21, 23, 41, 42, 43]",
                            "[3, 5, 11, 16, 32, 38]",
                            "[7, 11, 16, 35, 36, 44]",
                            "[1, 8, 11, 31, 41, 42]",
                            "[13, 14, 16, 38, 42, 45]",
                            "[7, 11, 30, 40, 42, 43]",
                            "[2, 13, 22, 32, 38, 45]",
                            "[1, 3, 5, 14, 22, 45]",
                            "3๊ฐœ ์ผ์น˜ (5,000์›) - 1๊ฐœ",
                            "4๊ฐœ ์ผ์น˜ (50,000์›) - 0๊ฐœ",
                            "5๊ฐœ ์ผ์น˜ (1,500,000์›) - 0๊ฐœ",
                            "5๊ฐœ ์ผ์น˜, ๋ณด๋„ˆ์Šค ๋ณผ ์ผ์น˜ (30,000,000์›) - 0๊ฐœ",
                            "6๊ฐœ ์ผ์น˜ (2,000,000,000์›) - 0๊ฐœ",
                            "์ด ์ˆ˜์ต๋ฅ ์€ 62.5%์ž…๋‹ˆ๋‹ค."
                    );
                },
                List.of(8, 21, 23, 41, 42, 43),
                List.of(3, 5, 11, 16, 32, 38),
                List.of(7, 11, 16, 35, 36, 44),
                List.of(1, 8, 11, 31, 41, 42),
                List.of(13, 14, 16, 38, 42, 45),
                List.of(7, 11, 30, 40, 42, 43),
                List.of(2, 13, 22, 32, 38, 45),
                List.of(1, 3, 5, 14, 22, 45)
        );
    }

์œ„ ์ฝ”๋“œ๋Š” ๋กœ๋˜ ๊ฒŒ์ž„์˜ ์‹œ์ž‘ ๋ถ€ํ„ฐ ์ข…๋ฃŒ๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค.

  1. "8000"์„ ์ž…๋ ฅํ•œ๋‹ค.

  2. ๋กœ๋˜๋„˜๋ฒ„, ๋ณด๋„ˆ์Šค ๋„˜๋ฒ„๋ฅผ ์ž…๋ ฅํ•œ๋‹ค."1,2,3,4,5,6", "7"

  3. ์‹œ์Šคํ…œ์—์„œ๋Š”

            List.of(8, 21, 23, 41, 42, 43),
            List.of(3, 5, 11, 16, 32, 38),
            List.of(7, 11, 16, 35, 36, 44),
            List.of(1, 8, 11, 31, 41, 42),
            List.of(13, 14, 16, 38, 42, 45),
            List.of(7, 11, 30, 40, 42, 43),
            List.of(2, 13, 22, 32, 38, 45),
            List.of(1, 3, 5, 14, 22, 45)

8๊ฐœ์˜ ๋กœ๋˜๋ฅผ ๋ฐœํ–‰ํ•œ๋‹ค.

  1. ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

์œ„์—์„œ run, output ๋ฉ”์„œ๋“œ๊ฐ€ ์–ด๋–ค ๋กœ์ง์ธ์ง€ ํŒŒํ—ค์ณ ๋ณด๊ธฐ ์œ„ํ•ด NsTest๋ฅผ ์‚ดํŽด๋ณด์ž.

public abstract class NsTest {
    private PrintStream standardOut;
    private OutputStream captor;

    @BeforeEach
    protected final void init() {
        standardOut = System.out;
        captor = new ByteArrayOutputStream();// ๊ธฐ์กด Sytem.out์˜ ์ŠคํŠธ๋ฆผ ์ €์žฅ
        System.setOut(new PrintStream(captor));// System.out์œผ๋กœ ์ถœ๋ ฅํ•˜๋Š” ์ŠคํŠธ๋ฆผ์„ captor๋กœ ๋ณ€๊ฒฝ
    }

    @AfterEach
    protected final void printOutput() {
        System.setOut(standardOut); // ๊ธฐ์กด Sytem.out์ŠคํŠธ๋ฆผ์œผ๋กœ ์ถœ๋ ฅ ์ŠคํŠธ๋ฆผ ๋ณ€๊ฒฝ
        System.out.println(output());
    }

    protected final String output() {
        return captor.toString().trim();
    }

    protected final void run(final String... args) {
        try {
            command(args);
            runMain();
        } finally {
            Console.close();
        }
    }

    protected final void runException(final String... args) {
        try {
            run(args);
        } catch (final NoSuchElementException ignore) {
        }
    }

    private void command(final String... args) {
        final byte[] buf = String.join("\n", args).getBytes();
        System.setIn(new ByteArrayInputStream(buf));
    }

    protected abstract void runMain();
}

NsTest๋Š” ํ…Œ์ŠคํŠธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ฝ˜์†”์—์„œ ์ž…๋ ฅ๋ฐ›๊ฑฐ๋‚˜ ์ถœ๋ ฅํ•˜๋Š” ๊ฐ’๋“ค์„ ๋‚ด๋ถ€์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด System.setOut๊ณผ System.setIn์„ ์‚ฌ์šฉํ•œ๋‹ค. ๋จผ์ € ์ฝ˜์†” ์ถœ๋ ฅ๊ฐ’(System.out.println)์„ ๋‚ด๋ถ€ ๋ณ€์ˆ˜์— ์–ด๋–ป๊ฒŒ ๋‹ด๋Š”์ง€ ์•Œ์•„๋ณด์ž.

NsTest๋Š” BeforeEach์™€ AfterEach ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด Test ์ค‘์— System.out.println ๋ฉ”์„œ๋“œ๋กœ ์ฝ˜์†”์— ์ถœ๋ ฅํ•˜๋Š” ๊ฐ’์„ captor์— ๋‹ด์•„๋‘”๋‹ค.

  1. init ๋ฉ”์„œ๋“œ์—์„œ System.out์˜ ์ŠคํŠธ๋ฆผ์„ captor๋ฅผ ํ–ฅํ•˜๋„๋ก ๋ฐ”๊พผ๋‹ค. ์ฆ‰, ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์˜ ์ถœ๋ ฅ ๊ฐ’์„ captor๋กœ ๋‹ด์•„๋‘”๋‹ค.
  2. printOutput์—์„œ System.out์˜ ์ŠคํŠธ๋ฆผ์„ ์›์ƒ๋ณต๊ตฌํ•œ๋‹ค.

์ฝ˜์†”์—์„œ ์ž…๋ ฅํ•ด์•ผ ํ•˜๋Š” ๊ฐ’์€ ๋ฏธ๋ฆฌ command ๋ฉ”์„œ๋“œ์— String ๊ฐ’(String... args)์œผ๋กœ ์ „๋‹ฌํ•œ๋‹ค. ์ „๋‹ฌํ•œ String ๊ฐ’์€ byte ๋ฐฐ์—ด์ธ buf ๋ณ€์ˆ˜์— ๋‹ด๋Š”๋‹ค. ๊ทธ๋ฆฌ๊ณ  buf ๊ฐ’์„ ByteArrayInputStream ํ˜•ํƒœ๋กœ System.in ์ž…๋ ฅ ์ŠคํŠธ๋ฆผ์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ์ฆ‰, Scanner.nextLine ๋“ฑ์„ ํ˜ธ์ถœํ•ด ์ฝ˜์†”์—์„œ ์ž…๋ ฅ๊ฐ’์„ ๋ฐ›์„ ๋•Œ ์‹ค์ œ๋กœ ์ฝ˜์†”์—์„œ ์ž…๋ ฅํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ buf ๋ฐฐ์—ด ์•ˆ์— ๊ฐ’๋“ค์„ ์ฐจ๋ก€๋กœ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

ApplicationTest์—์„œ ์‚ฌ์šฉํ•˜๋Š” run๋ฉ”์„œ๋“œ๋Š” command๋ฉ”์„œ๋“œ์™€ runMain๋ฉ”์„œ๋“œ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค. command ๋ฉ”์„œ๋“œ๋Š” ๊ฒŒ์ž„ ์œ ์ €๊ฐ€ ์ž…๋ ฅํ•ด์•ผ ํ•˜๋Š” ์‚ฌ๋ ค๋Š” ๊ฐ’(8000), ๋กœ๋˜ ๋‹น์ฒจ ๋ฒˆํ˜ธ(1,2,3,4,5,6), ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ(7) ์„ ๋ฐ›๋Š”๋‹ค. ์œ„์—์„œ ์„ค๋ช…ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ command๋Š” ์ „๋‹ฌ๋ฐ›์€ ๋ฌธ์ž์—ด์„ System.in์˜ ์ž…๋ ฅ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋Œ€๊ธฐ์‹œํ‚จ๋‹ค. runMain๋ฉ”์„œ๋“œ๋Š” ApplicationTest์—์„œ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•œ ๋ฉ”์„œ๋“œ๋กœ ํ…Œ์ŠคํŠธ ํด๋ž˜์Šค Application์„ ์‹คํ–‰ํ•œ๋‹ค. Application์„ ์‹คํ–‰ํ•˜๋ฉด์„œ Scanner.nextLine()์„ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค command์— ์ „๋‹ฌํ•œ ๋ฌธ์ž์—ด ๊ฐ’์„ ๋ฆฌํ„ด๋ฐ›๋Š” ๊ฒƒ์ด๋‹ค.

๊ทธ๋Ÿผ ์ด์ œ assertRandomNumberInRangeTest๊ฐ€ ์–ด๋–ค ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋Š”์ง€ ์‚ดํŽด๋ณด์ž.

public static void assertRandomUniqueNumbersInRangeTest(
        final Executable executable,
        final List<Integer> value,
        final List<Integer>... values
    ) {
        assertRandomTest(
            () -> Randoms.**pickUniqueNumbersInRange**(anyInt(), anyInt(), anyInt()),
            executable,
            value,
            values
        );

assertRandomUniqueNumbersInRangeTest ๋ฉ”์„œ๋“œ๋Š” Executable, value, values๋ฅผ ์ „๋‹ฌ๋ฐ›๋Š”๋‹ค. ์ด๊ฒƒ์„ ๊ทธ๋Œ€๋กœ "() -> Ra*ndoms.pickUniqueNumbersInRange(anyInt(), anyInt(), anyInt())"์™€ ํ•จ๊ป˜ assertRandomTest ๋ฉ”์„œ๋“œ์— ์ „๋‹ฌํ•œ๋‹ค. assertRandomTest๋Š” ํ•œ๋งˆ๋””๋กœ verification์ด ํ˜ธ์ถœ๋œ๋‹ค๋ฉด value, values๋ฅผ* ๋ฌถ์€ ์–ด๋ ˆ์ด์˜ ๊ฐ’๋“ค์„ ์ฐจ๋ก€๋กœ ๋ฆฌํ„ดํ•ด, Executable์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

private static <T> void assertRandomTest(
        final Verification verification,
        final Executable executable,
        final T value,
        final T... values
    ) {
        assertTimeoutPreemptively(RANDOM_TEST_TIMEOUT, () -> {
            try (final MockedStatic<Randoms> mock = mockStatic(Randoms.class)) {
                mock.when(verification).thenReturn(value, Arrays.stream(values).toArray());
                executable.execute();
            }
        });
    }

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