Mokito 모듈을 이용한 Random 객체 통제하기

2023. 3. 10. 12:54JAVA/Language

개요

코드스쿼드 부트캠프를 하면서 사다리 게임을 구현하던 도중 Random 객체를 사용할 일이 있었습니다. 그리고 단위 테스트에서 Random 객체를 사용할 수 밖에 없었고 Random 객체의 nextBoolean() 메서드 실행시 제가 원하는 값과 순서로 반환되기를 원하였습니다. 이 글에서는 Mokito 모듈을 이용하여 Random 객체의 nextBoolean() 메서드 호출시 어떻게 하면 원하는 값(true 또는 false)을 반환하게 하고 어떤 순서로 설정할 수 있는지 알아봅니다.

 

Random 객체를 다루면서 했던 실수

저는 보통 Random 객체를 생성할때 외부에서 생성자로 주입받는 방식이 아닌 생성자 내부에서 필드 멤버인 Random 멤버에 객체를 생성하는 방식으로 생성하였습니다.

class Person {

    private Random random;

    public Person() {
        this.random = new Random();
    }

    public boolean sayYesOrNo() {
        return random.nextBoolean();
    }
}

위와 같은 코드의 문제점은 Person 객체 생성시 random 객체를 Mock 객체로 넣기 위해서는 리플렉션(Reflection) 기술을 이용하여 넣을 수 밖에 없었습니다.

 

하지만 리플렉션 기술을 사용하게 되면 외부에서 random 객체를 참조하게 되는 것이므로 결합도가 높아지고 유지보수 비용이 증가하는 문제점을 가지고 있습니다. 예를 들어 random 멤버의 이름을 변경하게 되면 외부에서 리플렉션 기술을 통해 random 멤버를 참조하는 쪽에서 런타임 에러가 발생할 수 있습니다.

 

또한 리플렉션 기술을 사용하게 되면 컴파일 에러가 발생하지 않고 런타임 에러가 발생하는 문제점을 가지고 있습니다. 이는 사전에 에러를 확인할 수 없고 프로그램을 실행하는 과정에서 에러가 발생한 것을 인지한다는 의미입니다.

 

따라서 위와 같이 단위 테스트와 같은 외부에서 객체 생성시 random 객체를 Mock 객체로 넣기 위해서는 생성자 매개변수를 통해서 외부에서 주입하는 방식을 하여야 합니다.

 

Mockito 모듈을 이용한 Random 객체 통제

의존성 추가

testImplementation 'org.mockito:mockito-core:5.1.1'

 

단위 테스트 및 클래스 작성

public class MokitoTest {

    @Test
    @DisplayName("Person 객체 생성시 목 객체를 주입하여 랜덤 객체가 통제되는지 테스트")
    public void sayYesOrNo() {
        //given
        Random mockRandom = Mockito.mock(Random.class);
        Mockito.when(mockRandom.nextBoolean()).thenReturn(true, false);
        Person person = new Person(mockRandom);
        //when
        boolean actual1 = person.sayYesOrNo();
        boolean actual2 = person.sayYesOrNo();
        //then
        Assertions.assertThat(actual1).isTrue();
        Assertions.assertThat(actual2).isFalse();
    }
}

class Person {

    private Random random;

    public Person(Random random) {
        this.random = random;
    }

    public boolean sayYesOrNo() {
        return random.nextBoolean();
    }
}

위와 같이 Random 객체를 생성자의 매개변수를 통해서 주입받게 되면 단위 테스트에서 Mock 객체를 주입할 수 있습니다. 또한 단위 테스트의 Mock 객체 뿐만 아니라 Product 코드에서도 다양한 Random 객체를 객체 생성시 주입하여 생성할 수 있는 장점이 있습니다.

 

 

Mock 객체 생성

Random mockRandom = Mockito.mock(Random.class);

Mockito.mock() 메서드의 매개변수로 만들고자 하는 Mock 객체의 클래스 타입을 넣어주시면 됩니다.

 

Mock 객체의 특정 메서드의 반환값 및 순서 설정

Mockito.when(mockRandom.nextBoolean()).thenReturn(true, false);

위와 같이 Mockito.when() 메서드의 매개변수에 특정 메서드의 호출을 넣습니다.

 

그리고 thenReturn 메서드의 매개변수에는 nextBoolean()를 실행하고 반환할 값을 설정하면 됩니다.