0 + 프로그래밍/0 + Java

제어할 수 없는 코드가 포함된 로직을 메소드 변경 없이 테스트 코드를 작성하는 방법(오버라이딩)

힘들면힘을내는쿼카 2023. 11. 20. 10:57
728x90
반응형

제어할 수 없는 코드가 포함된 로직을 메소드 변경 없이 테스트 코드를 작성하는 방법(오버라이딩)

 

 

제어할 수 없는 코드가 포함된 레거시 코드를 받은 당신 🫵

당신은 아래의 레거시 코드를 받았고, move라는 코드의 테스트 코드를 작성해야한다.


이때 당신은 어떻게 해야할 것인가?

public class Car {
    public static final int FORWARD_NUMBER = 1;
    private int position;

    public void move() {
        if (getRandom() >= FORWARD_NUMBER) {
            position++;
        }
    }

    private int getRandom() {
        return Randoms.pickNumberInRange(0, 9);
    }

    public int getPosition() {
        return position;
    }
}

 

getRandom()을 보니 내가 직접 제어할 수 없는 부분이다.
따라서 테스트 코드를 작성하면 경우에 따라서 성공할 수도 실패할 수도 있다.

class CarTest {
    @Test
    @DisplayName("1칸 이동")
    void forward() {
        // given
        Car car = new Car();
        // when
        car.move();
        // then
        assertThat(car.getPosition()).isEqualTo(1);
    }

    @Test
    @DisplayName("정지")
    void stop() {
        // given
        Car car = new Car();
        // when
        car.move();
        // then
        assertThat(car.getPosition()).isEqualTo(0);
    }
}

 

내가 제어 할 수 없으니까, move메소드에 파라미터를 받도록 변경하자! 🥰

public class Car {
    public static final int FORWARD_NUMBER = 1;
    private int position;

    public void move(int randomNumber) {
        if (randomNumber >= FORWARD_NUMBER) {
            position++;
        }
    }

    private int getRandom() {
        return Randoms.pickNumberInRange(0, 9);
    }

    public int getPosition() {
        return position;
    }
}

 

이렇게 변경하면, 우리는 randomNumber를 통해 손쉽게 테스트 할 수 있다.

(제어할 수 없는 부분을 우리가 제어할 수 있게 변경했다.)

class CarTest {

    @Test
    @DisplayName("1칸 이동")
    void forward() {
        // given
        Car car = new Car();
        // when
        car.move(1);
        // then
        assertThat(car.getPosition()).isEqualTo(1);
    }

    @Test
    @DisplayName("정지")
    void stop() {
        // given
        Car car = new Car();
        // when
        car.move(0);
        // then
        assertThat(car.getPosition()).isEqualTo(0);
    }
}

 

 

오버라이딩

그런데, move를 변경하려고 했을 때 move가 사용되는 클래스가 1,000개가 넘는 상황이여서
메소드를 변경하게 되면 어떤 영향이 생길지 예측할 수 없다고 가정해보자…(😰 무서워…)

 

move 메소드를 변경하지 않고, move를 테스트 할 수 있는 코드를 작성하려면 어떻게 해야할까…? 🤔

 

 

생각보다 간단하다. 😊

 

getRandom()메소드의 접근권한을 private에서 protected로 변경하면 된다.!

public class Car {
    public static final int FORWARD_NUMBER = 1;
    private int position;

    public void move() {
        if (getRandom() >= FORWARD_NUMBER) {
            position++;
        }
    }

    public void move(int randomNumber) {
        if (randomNumber >= FORWARD_NUMBER) {
            position++;
        }
    }

    // private를 protected로 변경한다!
    protected int getRandom() {
        return Randoms.pickNumberInRange(0, 9);
    }

    public int getPosition() {
        return position;
    }
}

 

왜 변경..하는거지….?

변경하면 뭐가 달라지는 거야..?🤷🏻‍♂️

 

바로 테스트 코드를 작성할 때, 오버라딩(재정의) 할 수 있기 때문이다!!!

class CarTest {
    @Test
    @DisplayName("1칸 이동")
    void forward() {
        // given
        Car car = new Car() {
            @Override
            protected int getRandom() {
                return 1;
            }
        };
        // when
        car.move();
        // then
        assertThat(car.getPosition()).isEqualTo(1);
    }

    @Test
    @DisplayName("정지")
    void stop() {
        // given
        Car car = new Car() {
            @Override
            protected int getRandom() {
                return 0;
            }
        };
        // when
        car.move();
        // then
        assertThat(car.getPosition()).isEqualTo(0);
    }
}

 

정말로 대박인거 같다. 👍

 

결론

  • 레거시 코드에 내가 제어할 수 없는 코드가 포함되어 있는 로직이 있을 때, 테스트 코드를 작성하기 위해서 오버라이딩을 생각해보면 좋다!

  

참고

 

플레이그라운드

 

edu.nextstep.camp

 

 

 

  

728x90
반응형