Light Blue Pointer
본문 바로가기
Developing/개발일지

2023-11-29, Today I Learned

by Greedy 2023. 11. 29.

오늘 생각한 것

코테 풀다가 어떤 문제에서 내가 정한 20분이라는 기준을 넘기고도 문제풀이가 엉망진창이라 패닉했다

이런 실력을 가지고 여태까지 왜 괜찮아하면서 살았을까, 더 노력했었어야 하는거 아닐까 하는 생각을 하는데 당연히 문제에 집중이 안 돼서 더 잘 풀릴리가 없다

그러다가 그냥 마음을 차분히 가라앉히고 나는 나의 최선을 다 하자 이런 생각을 하며 찬찬히 다시 살펴보니까 내가 어느 부분에서 실수했는지 보였고 코드를 정리해 나가니까 괜찮아졌고 코드 제출에도 성공했다

내가 개발자(취준생)으로 정신건강을 유지하며 살 수 있는 방법은 그냥 침착한 자세를 유지하면서 최선을 다 하는 것일 거라고 생각하게 되었다

그리고 오늘 저번에 공부한 내용이랑 겹치는 것이 많아서

Controller 테스트 할때 필터 내용 나오는 것, 카카오 API사용에서 RestTemplate내용 나오는것 등

저번에 공부한 것들 복습했는데 그러다가

필터 체인 파트를 보게 됨

필터가 다른 필터로 넘어가는 순서가 있다, 근데 마지막 필터가 끝나면 어디로 가는거지? 라는 의문이 들었다

필터 -> DispatcherServlet 으로 동작한다고 하는데

나는 웹이나 Spring이 어떻게 동작하는지 개념이 아직도 안 잡힌 거 같다고 생각했다

내일부터는 지엽적인 것에 집착하는 것보다 큰 흐름을 이해하면서 좀 더 감을 잡아보려고 한다

오늘 배운것

⚠️import java.util.Math; 이거 아님 import java.lang.Math;임

 

⚠️IntelliJ 에서 테스트 그룹이랑 DisplayedName이 안 뜨던거

Setting → Build,Execution,Deployment → Build Tools → Gradle → Run tests using IntelliJ IDEA로 바꾸고 괜찮아짐

JUnit5 테스트

Before - After

@BeforeEach

@BeforeEach
void setUp() {
    System.out.println("각각의 테스트 코드가 실행되기 전에 수행");
}
  • 각각의 테스트 코드가 실행되기 전에 수행됨

@BeforeAll

@BeforeAll
static void beforeAll() {
    System.out.println("모든 테스트 코드가 실행되기 전에 최초로 수행\\n");
}
  • 모든 테스트 코드가 수행되기 전에 최초로 수행됨
  • static 메서드(필수!)

@AfterEach

@AfterEach
void tearDown() {
    System.out.println("각각의 테스트 코드가 실행된 후에 수행\\n");
}
  • 각각의 테스트 코드가 실행된 후에 수행됨

@AfterAll

@AfterAll
static void afterAll() {
    System.out.println("모든 테스트 코드가 수행된 후 마지막으로 수행");
}
  • 모든 테스트 코드가 수행된 후 마지막으로 수행됨
  • static 메서드(필수!)

 

 

@DisplayName

@Test
@DisplayName("테스트의 내용을 한눈에 알아볼 수 있게 네이밍 해줄 수 있습니다.")
void test1() {
    System.out.println("테스트의 수행 내용들을 빠르게 파악할 수 있습니다.");
}
  • 테스트 내용을 한눈에 알아볼 수 있게 네이밍
  • 테스트 수행 내용 빠르게 파악가능

@Nested

@Nested
@DisplayName("주제 별로 테스트를 그룹지어서 파악하기 좋습니다.")
class Test1 {
    @Test
    @DisplayName("Test1 - test1()")
    void test1() {
        System.out.println("Test1.test1");
    }

    @Test
    @DisplayName("Test1 - test2()")
    void test2() {
        System.out.println("Test1.test2");
    }
}

@Nested
@DisplayName("Test2 다른 주제")
class Test2 {
    @Test
    @DisplayName("Test2 - test1()")
    void test1() {
        System.out.println("Test2.test1");
    }

    @Test
    @DisplayName("Test2 - test2()")
    void test2() {
        System.out.println("Test2.test2");
    }
}
  • 주제별로 테스트를 그룹지어서 파악하기에 굿

@Order

@Nested
@DisplayName("주제 별로 테스트를 그룹지어서 파악하기 좋습니다.")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class Test1 {

    @Order(1)
    @Test
    @DisplayName("Test1 클래스")
    void test() {
        System.out.println("\\nTest1 클래스");
    }

    @Order(3)
    @Test
    @DisplayName("Test1 - test1()")
    void test1() {
        System.out.println("Test1.test1");
    }

    @Order(2)
    @Test
    @DisplayName("Test1 - test2()")
    void test2() {
        System.out.println("Test1.test2");
    }
}
  • @TestMethodOrder(MethodOrderer.OrderAnnotation.class) : 테스트를 메서드 단위로 순서를 부여
  • 메서드에 @Order(순서) 애너테이션을 추가

 

package com.sparta.junit5practice;

import org.junit.jupiter.api.*;

public class BeforeAfterTest {
    @BeforeEach
    void setUp() {
        System.out.println("각각의 테스트 코드가 실행되기 전에 수행");
    }

    @BeforeAll
    static void beforeAll() {
        System.out.println("모든 테스트 코드가 실행되기 전에 최초로 수행\\n");
    }

    @AfterEach
    void tearDown() {
        System.out.println("각각의 테스트 코드가 실행된 후에 수행\\n");
    }

    @AfterAll
    static void afterAll() {
        System.out.println("모든 테스트 코드가 수행된 후 마지막으로 수행");
    }

    @Test
    @DisplayName("테스트의 내용을 한눈에 알아볼 수 있게 네이밍 해줄 때")
    void test1(){
        System.out.println("테스트코드 작성 1");
    }

    @Test
    void test2(){
        System.out.println("테스트코드 작성 2");
    }

    @Nested
    @DisplayName("주제 별로 테스트를 그룹지어서 파악하기 좋습니다.")
    @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
    class Test1 {

        @Order(1)
        @Test
        @DisplayName("Test1 클래스")
        void test() {
            System.out.println("\\nTest1 클래스");
        }

        @Order(3)
        @Test
        @DisplayName("Test1 - test1()")
        void test1() {
            System.out.println("Test1.test1");
        }

        @Order(2)
        @Test
        @DisplayName("Test1 - test2()")
        void test2() {
            System.out.println("Test1.test2");
        }
    }

    @Nested
    @DisplayName("Test2 다른 주제")
    @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
    class Test2 {
        @Test
        @DisplayName("Test2 - test1()")
        void test1() {
            System.out.println("Test2.test1");
        }

        @Test
        @DisplayName("Test2 - test2()")
        void test2() {
            System.out.println("Test2.test2");
        }
    }
}

실행 결과

모든 테스트 코드가 실행되기 전에 최초로 수행

각각의 테스트 코드가 실행되기 전에 수행
테스트코드 작성 1
각각의 테스트 코드가 실행된 후에 수행

각각의 테스트 코드가 실행되기 전에 수행
테스트코드 작성 2
각각의 테스트 코드가 실행된 후에 수행

각각의 테스트 코드가 실행되기 전에 수행
Test2.test1
각각의 테스트 코드가 실행된 후에 수행

각각의 테스트 코드가 실행되기 전에 수행
Test2.test2
각각의 테스트 코드가 실행된 후에 수행

각각의 테스트 코드가 실행되기 전에 수행

Test1 클래스
각각의 테스트 코드가 실행된 후에 수행

각각의 테스트 코드가 실행되기 전에 수행
Test1.test2
각각의 테스트 코드가 실행된 후에 수행

각각의 테스트 코드가 실행되기 전에 수행
Test1.test1
각각의 테스트 코드가 실행된 후에 수행

모든 테스트 코드가 수행된 후 마지막으로 수행

Q. 왜 Test1이 먼저 써있는데 나중에 수행되지?

Order이 달리면 가장 나중에 수행하나?

테스트 반복하기

@RepeatedTest

 for문st

@RepeatedTest(value = 5, name = "반복 테스트 {currentRepetition} / {totalRepetitions}")
void repeatTest(RepetitionInfo info) {
    System.out.println("테스트 반복 : " + info.getCurrentRepetition() + " / " + info.getTotalRepetitions());
}
  • @RepeatedTest를 사용하여 테스트 메서드를 반복
  • name 속성을 사용하여 네이밍
  • RepetitionInfo 값을 파라미터로 받아서 현재 반복 횟수와 총 횟수 값을 확인

실행 결과

테스트 반복 : 1 / 5
테스트 반복 : 2 / 5
테스트 반복 : 3 / 5
테스트 반복 : 4 / 5
테스트 반복 : 5 / 5

왼쪽에는

✔️RepeatTest
	✔️repeatedTest(RepetitionInfo)
		✔️반복 테스트 1/5
		✔️반복 테스트 2/5
		✔️반복 테스트 3/5
		✔️반복 테스트 4/5
		✔️반복 테스트 5/5

이렇게 뜬다

@ParameterizedTest

@DisplayName("파라미터 값 활용하여 테스트 하기")
@ParameterizedTest
@ValueSource(ints = {1, 2, 3, 4, 5, 6, 7, 8, 9})
void parameterTest(int num) {
    System.out.println("5 * num = " + 5 * num);
}
  • @ParameterizedTest를 사용하여 파라미터를 받아 테스트할 수 있는 메서드 생성가능
  • @ValueSource(ints = {1, 2, 3, 4, 5, 6, 7, 8, 9})를 사용하여 파라미터 값을 전달
    • 전달되는 파라미터 수 만큼 테스트 메서드가 수행됨
    • int, String 등 여러 타입의 파라미터를 전달할 수 있음

실행결과

5 * num = 5
5 * num = 10
5 * num = 15
5 * num = 20
5 * num = 25
5 * num = 30
5 * num = 35
5 * num = 40
5 * num = 45

왼쪽 결과

✔️RepeatTest
	✔️파라미터 값 활용하여 테스트
		✔️[1] 1
		✔️[2] 2
		...
		✔️[9] 9
		✔️[10] 10
		

 

 

 

Assertions.assertEquals(expected, actual)

@Test
    @DisplayName("assertEquals")
    void test1() {
        Double result = calculator.operate(5, "/", 2);
        assertEquals(/*예상값*/2.5, /*결과값*/result);
    }
@Test
    @DisplayName("assertEquals - Supplier")
    void test1_1() {
        Double result = calculator.operate(5, "/", 0);
        // 테스트 실패 시 메시지 출력 (new Supplier<String>())
        assertEquals(/*예상값*/2.5, /*결과값*/result, /*메시지 출력*/() -> "연산자 혹은 분모가 0이 아닌지 확인해보세요!");
    }

Q. Supplier이 메시지 전달해주는 건가?

실행 결과

org.opentest4j.AssertionFailedError: 연산자 혹은 분모가 0이 아닌지 확인해보세요! ==>
Expected :2.5
Actual   :null
@Test
    @DisplayName("assertNotEquals")
    void test1_2() {
        Double result = calculator.operate(5, "/", 0);
        assertNotEquals(2.5, result);
    }

통과! 얘는 안 같은지 확인해줌

Assertions.assertTrue(boolean)

@Test
@DisplayName("assertTrue 와 assertFalse")
void test2() {
    assertTrue(calculator.validateNum(9));
    assertFalse(calculator.validateNum(0));
}

assertTrue() 메서드는 해당 파라미터 값이 true인지 확인

Assertions.assertNotNull(actual)

@Test
@DisplayName("assertNotNull 과 assertNull")
void test3() {
    Double result1 = calculator.operate(5, "/", 2);
    assertNotNull(result1);
    Double result2 = calculator.operate(5, "/", 0);
    assertNull(result2);
}
  • assertNotNull() 메서드는 해당 파라미터 값이 null이 아님을 확인

Assertions.assertThrows(expectedType, executable)

public Double operate(double num1, String op, double num2) {
        switch (op) {
            default:
                throw new IllegalArgumentException("잘못된 연산자입니다.");
        }
@Test
@DisplayName("assertThrows")
void test4() {
    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> calculator.operate(5, "?", 2));
    assertEquals("잘못된 연산자입니다.", exception.getMessage());
}
  • assertThrows( Exception 클래스 타입,실행 코드)
  • 실행 코드의 결과가 예상한 해당 클래스 타입이라면 테스트에 성공

Given - When - Then

  • Given-When-Then 패턴은 Test Code 스타일을 표현하는 방식

Given

  • 테스트 하고자하는 대상을 실제로 실행하기 전에 테스트에 필요한 값(상태)을 미리 선언

When

  • 테스트 하고자하는 대상을 실제로 실행 

Then

  • 어떤 특정한 행동(테스트 대상 실행) 때문에 발생할거라고 예상되는 결과에 대해 예측하고 맞는지 확인

Given - When - Then Ex1)

class CalculatorTest {

    Calculator calculator;

    @BeforeEach
    void setUp() {
        calculator = new Calculator();
    }

    @Test
    @DisplayName("계산기 연산 성공 테스트")
    void test1() {
        // given
        int num1 = 5;
        String op = "/";
        int num2 = 2;

        // when
        Double result = calculator.operate(num1, op, num2);

        // then
        assertNotNull(result);
        assertEquals(2.5, result);
    }

    @Test
    @DisplayName("계산기 연산 실패 테스트 : 분모가 0일 경우")
    void test1_1() {
        // given
        int num1 = 5;
        String op = "/";
        int num2 = 0;

        // when
        Double result = calculator.operate(num1, op, num2);

        // then
        assertNull(result);
    }

    @Test
    @DisplayName("계산기 연산 실패 테스트 : 연산자가 잘못됐을 경우")
    void test1_2() {
        // given
        int num1 = 5;
        String op = "?";
        int num2 = 2;

        // when - then
        IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> calculator.operate(5, "?", 2));
        assertEquals("잘못된 연산자입니다.", exception.getMessage());
    }
}

 

'Developing > 개발일지' 카테고리의 다른 글

2023-12-04, Today I Learned  (0) 2023.12.04
2023-11-30, Today I Learned  (0) 2023.11.30
2023-11-28, Today I Learned  (0) 2023.11.28
2023-11-23, Today I Learned  (0) 2023.11.24
2023-11-22, Today I Learned  (0) 2023.11.22