우테코 프리코스 테스트 코드 뜯어보기🔨
카테고리:
tag #
2023년 10월 25일
// Links to the libraries needed
우선 이 클래스의 선언문부터 보면 NsTest를 상속받고 있습니다.
class AdditionalTest extends NsTest
NsTest는 abstract로 클래스가 정의되어있고 2개의 필드와 7개의 메소드가 선언되어 있는 것을 확인할 수 있었습니다.
public abstract class NsTest {
private PrintStream standardOut;
private OutputStream captor;
@BeforeEach
protected final void init() {...}
@AfterEach
protected final void printOutput() {...}
protected final String output() {return captor.toString().trim();}
protected final void run(final String... args) {...}
protected final void runException(final String... args) {...}
private void command(final String... args) {...}
protected abstract void runMain();
@BeforeEach의 클래스는 아래와 같이 되어있네요
@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@API(status = STABLE, since = "5.0")
public @interface BeforeEach {
}
@BeforeEach
protected final void init() {
standardOut = System.out;
captor = new ByteArrayOutputStream();
System.setOut(new PrintStream(captor));
}
@AfterEach
protected final void printOutput() {
System.setOut(standardOut);
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) {
}
}
엥 그러면 String배열로 받아진다는 얘기일까요? 한번 사용해봅시다.
public static void minje(String... s){
System.out.println(Arrays.toString(s));
}
public static void main(String[] args) {
minje("kim","min","je");
}
}
=>[kim, min, je]
private void command(final String... args) {
final byte[] buf = String.join("\n", args).getBytes();
System.setIn(new ByteArrayInputStream(buf));
}
static void runException(final String... args) {
for(String i : args){
System.out.println(i);
}
final byte[] buf = String.join("\n", args).getBytes();
for(int i : buf){
System.out.println(i);
}
}
public static void main(String[] args) {
runException("kim", "min", "je");
}
=>kim
min
je
107
105
109
10
109
105
110
10
106
101
protected abstract void runMain();
class ApplicationTest extends NsTest {
@Test
void 게임종료_후_재시작() {...}
@Test
void 예외_테스트() {...}
@Override
public void runMain() {...}
@Override
public void runMain() {
Application.main(new String[]{});
}
@Test
void 게임종료_후_재시작() {
assertRandomNumberInRangeTest(
() -> {
run("246", "135", "1", "597", "589", "2");
assertThat(output()).contains("낫싱", "3스트라이크", "1볼 1스트라이크", "3스트라이크", "게임 종료");
},
1, 3, 5, 5, 8, 9
);
}
public static void assertRandomNumberInRangeTest(
final Executable executable,
final Integer value,
final Integer... values
) {
assertRandomTest(
() -> Randoms.pickNumberInRange(anyInt(), anyInt()),
executable,
value,
values
);
}
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();
}
});
}
assertTimeoutPreemptively(RANDOM_TEST_TIMEOUT() -> {})
private static final Duration *RANDOM_TEST_TIMEOUT* = Duration.*ofSeconds*(10L);
try (final MockedStatic<Randoms> mock = mockStatic(Randoms.class))
mock.when(verification).thenReturn(value, Arrays.stream(values).toArray());
public static void assertRandomNumberInRangeTest(
final Executable executable,
final Integer value,
final Integer... values
) {
assertRandomTest(
() -> Randoms.pickNumberInRange(anyInt(), anyInt()),
executable,
value,
values
);
}
void 게임종료_후_재시작() {
assertRandomNumberInRangeTest(
() -> {
run("246", "135", "1", "597", "589", "2");
assertThat(output()).contains("낫싱", "3스트라이크", "1볼 1스트라이크", "3스트라이크", "게임 종료");
},
1, 3, 5, 5, 8, 9
);
}
executable 매개변수로는
() -> {
run("246", "135", "1", "597", "589", "2");
assertThat(output()).contains("낫싱", "3스트라이크", "1볼 1스트라이크", "3스트라이크", "게임 종료");
},
@Test
void 예외_테스트() {
assertSimpleTest(() ->
assertThatThrownBy(() -> runException("1234"))
.isInstanceOf(IllegalArgumentException.class)
);
}
private static final Duration SIMPLE_TEST_TIMEOUT = Duration.ofSeconds(1L);
public static void assertSimpleTest(final Executable executable) {
assertTimeoutPreemptively(SIMPLE_TEST_TIMEOUT, executable);
}
() -> assertThatThrownBy(() -> runException("1234"))
.isInstanceOf(IllegalArgumentException.class)
assertThatThrownBy의 API설명으로는 “If the provided ThrowableAssert.ThrowingCallable does not raise an exception, an error is immediately thrown, in that case the test description provided with as(String, Object…) is not honored.”
→ 주어진 메소드 실행에 대한 반환값이 예외를 발생시키지 않으면 오류를 발생한다고 합니다.