SW/Java

단위시험 유지관리성 향상

얇은생각 2023. 12. 11. 07:30
반응형

단위 테스트를 작성하는 것이 때때로 고통스러울 수 있습니다. 이지랜덤으로 단위 테스트의 유지 관리성을 향상시키는 방법을 알아보겠습니다.

단위 테스트를 할 때, 여러분은 아마 객체를 몇 번이고 만들어야 하는 상황에 처해 있다는 것을 발견했을 것입니다. 이를 위해서는 해당 매개변수를 가진 클래스 생성자에게 전화해야 합니다. 지금까지 특이한 사항은 없었지만, 아마도 이 필드들 중 일부의 값이 테스트와 무관하거나 단순히 생성자에서 필수 항목이라는 이유로 중첩된 "더미" 객체를 생성해야 하는 경우가 있었을 것입니다.

이 모든 것은 아마도 어느 시점에서 좌절감을 자아내게 했고, 여러분이 제대로 하고 있는지에 대해 의문을 갖게 했을 것입니다. 만약 그것이 정말로 단위 테스트를 할 수 있는 방법이라면, 노력할 가치가 없을 것입니다.

, 일반적으로 검사는 명확한 목적을 가져야 합니다. 따라서 SUT(검사 대상 시스템) 내에는 실제로 검사의 대상이 되는 필드가 있고, 반면 다른 필드는 관련이 없을 것으로 예상됩니다.

예를 들어보자. 이름, 이메일 및 연령 필드가 있는 "Person" 클래스가 있다고 가정하자. 다른 한편으로, 우리는 Person 객체를 수신하여 이 객체가 버스로 무료로 여행할 수 있는지 여부를 알려주는 서비스의 단위 테스트를 하고자 합니다. 우리는 이 계산이 단지 나이에 따라 다르다는 것을 알고 있습니다. 14세 미만의 어린이는 무료로 여행한다. 따라서 이 경우에는 Name Email 필드는 무관합니다.

이 예에서는 사용자 개체를 만드는 데 큰 노력이 필요하지 않지만 사용자 클래스의 필드가 커지거나 중첩된 개체가 표시된다고 가정합니다. 주소, 친척(사용자 목록), 전화 목록 등. 이제 고려해야 할 몇 가지 문제가 있습니다:

  • 물건을 만드는 것이 더 힘이 듭니다.
  • 수업의 시공자나 분야가 바뀌면 어떻게 됩니까?
  • 객체 목록이 있을 때 몇 개의 객체를 만들어야 합니까?
  • 테스트에 영향을 주지 않는 필드에는 어떤 값을 할당해야 합니까?
  • 변동성 없이 값이 항상 동일하면 좋습니까?

 

이 상황을 해결하기 위해 보통 잘 알려진 두 가지 디자인 패턴, Object Mother Builder가 사용됩니다. 두 경우 모두, 우리가 필요로 하는 특성을 가진 물건들을 쉽게 만들 수 있는 "도우미"를 갖는 것이 아이디어입니다.

두 가지 접근법 모두 광범위하고, 적절하며, 검사의 유지 가능성을 선호합니다. 그러나, 그들은 여전히 몇 가지 문제를 해결하지 못합니다:

  • 생성자를 변경할 때는 테스트에 영향을 주지 않는 필드라도 코드가 컴파일을 중지합니다.
  • 새 필드가 나타나면 테스트할 개체를 생성하는 코드를 업데이트해야 합니다.
  • 중첩 개체를 생성하는 작업은 여전히 어렵습니다.
  • 필수 필드와 사용되지 않는 필드는 하드 코드화되어 기본적으로 할당되므로 검정에는 변동성이 없습니다.

 

이런 문제들을 해결할 수 있는 자바 라이브러리 중 하나가 "이지랜덤"입니다. 다음으로, 우리는 자바 라이브러리의 작동에 대한 세부사항을 볼 것입니다.

 

 

단위시험 유지관리성 향상

 

 

EasyRandom이란?

이지랜덤은 자바 라이브러리로 단위 및 적분 테스트를 위한 랜덤 데이터 생성을 용이하게 합니다. 이지랜덤 뒤에 숨겨진 아이디어는 테스트에서 사용할 수 있는 랜덤 값으로 객체를 생성하는 간단한 방법을 제공하는 것입니다. 이지랜덤은 각 테스트에서 클래스 속성별 값을 수동으로 정의하는 대신 이 과정을 자동화하여 각 속성별 랜덤 데이터를 자동으로 생성합니다.

이 라이브러리는 원시 데이터 유형, 사용자 지정 클래스, 컬렉션 및 기타 유형의 개체를 처리합니다. 또한 특정 규칙 및 데이터 생성 제한을 존중하도록 구성할 수 있으므로 상당히 유연합니다.

EasyRandom을 사용하여 랜덤 개체를 생성하는 기본적인 예는 다음과 같습니다:

public class EasyRandomExample {
    public static void main(String[] args) {

        EasyRandom easyRandom = new EasyRandom();

        Person randomPerson = easyRandom.nextObject(Person.class);
        System.out.println(randomPerson);
    }
}

 

 

이 예제에서 Person은 더미 클래스이며 easyRandom.nextObject(Person.class)는 속성에 대한 랜덤 값을 가진 Person의 인스턴스를 생성합니다.

이 객체들의 생성은 클래스 컨스트럭터에 의존하지 않으므로 SUT에 변경이 있더라도 테스트 코드는 계속 컴파일될 것입니다. 이렇게 하면 자동 테스트 제품군을 유지하는 데 가장 큰 문제 중 하나가 해결됩니다.

 

 

왜 흥미로울까요?

EasyRandom 라이브러리를 사용하여 애플리케이션을 테스트하면 다음과 같은 몇 가지 이점이 있습니다:

단순화된 랜덤 데이터 생성: 개체에 대한 랜덤 데이터 생성을 자동화하여 테스트마다 반복적인 코드를 작성하지 않아도 됩니다.

단위 및 통합 테스트 용이: 테스트 객체를 자동으로 생성하여 테스트 데이터를 수동으로 생성하는 대신 코드의 동작을 테스트하는 데 집중할 수 있습니다.

데이터 사용자 지정: 기본적으로 랜덤 데이터를 생성하지만, EasyRandom을 사용하면 필요에 따라 특정 필드 또는 속성을 사용자 지정할 수 있으므로 필요에 따라 생성을 조정할 수 있습니다.

인적 오류 감소: 특히 많은 필드와 조합을 다룰 때 테스트 데이터를 수동으로 생성하면 오류가 발생할 수 있습니다. 이지랜덤은 일관된 무작위 데이터를 생성하여 인적 오류를 최소화하는 데 도움이 됩니다.

Simplified Maintenance: 클래스 요구사항이 변경될 경우(새 필드, 유형 등) EasyRandom에서 테스트 데이터를 자동으로 생성하므로 수동으로 업데이트할 필요가 없습니다.

가독성 향상: EasyRandom을 사용하면 각 경우에 테스트 값을 명시적으로 정의할 필요가 없으므로 테스트가 더 깨끗하고 가독성이 높아집니다.

테스트 개발 속도 향상: 테스트 개체를 만드는 데 소요되는 시간을 단축하여 테스트를 보다 빠르고 효과적으로 개발할 수 있습니다.

사용 편의성: Java 프로젝트에 이 라이브러리를 추가하는 것은 실질적으로 즉각적이고 사용하기 매우 쉽습니다.

 

어디에 적용할 수 있습니까?

이 라이브러리를 사용하면 단위 테스트를 위한 개체 생성을 단순화할 수 있지만 테스트 데이터 세트를 생성해야 할 때도 큰 도움이 될 수 있습니다. 이는 응용 프로그램의 DTO를 사용하여 무작위 개체를 생성하여 나중에 데이터베이스나 파일에 덤프함으로써 달성할 수 있습니다. 권장되지 않는 경우: 개체 생성이 복잡하지 않거나 테스트에 관련된 개체의 모든 분야를 정확하게 제어해야 하는 프로젝트에서는 이 라이브러리가 가치가 없을 수 있습니다.

 

 

EasyRandom을 사용하는 방법

EasyRandom이 실제 예제, 사용 환경 및 필수 구성 요소와 함께 작동하는 모습을 살펴보겠습니다.

 

전제조건

자바 8+

메이븐 또는 그라들

 

초기 설정

프로젝트 내에 새로운 종속성을 추가해야 합니다. pom.xml 파일은 다음과 같습니다:

<dependency>
    <groupId>org.jeasy</groupId>
    <artifactId>easy-random-core</artifactId>
    <version>5.0.0</version>
</dependency>

 

 

기본 사용 사례

가장 기본적인 사용 사례는 이미 전에 본 적이 있습니다. 이 예제에서는 사람 클래스의 필드에 완전히 임의적인 방법으로 값이 할당됩니다. 분명히 테스트를 할 때 우리는 특정 필드를 제어해야 합니다. 이것을 예로 들어봅시다. 이지랜덤은 원시 유형에도 사용될 수 있음을 기억하세요. 따라서 우리의 예제는 다음과 같이 보일 수 있습니다.

public class PersonServiceTest {
    private final EasyRandom easyRandom = new EasyRandom();
    private final PersonService personService = new PersonService();

    @Test
    public void testIsAdult() {
        Person adultPerson = easyRandom.nextObject(Person.class);
   
        adultPerson.setAge(18 + easyRandom.nextInt(80));

        assertTrue(personService.isAdult(adultPerson));
    }

    @Test
    public void testIsNotAdult() {
        Person minorPerson = easyRandom.nextObject(Person.class);

        minorPerson.setAge(easyRandom.nextInt(17));

        assertFalse(personService.isAdult(minorPerson));
    }
}

 

 

보다시피, 이러한 테스트 객체 생성 방식은 "Person" 클래스의 변화로부터 우리를 보호하고 우리가 관심 있는 분야에만 집중할 수 있게 합니다.

또한 이 라이브러리를 사용하여 무작위 개체 목록을 생성할 수 있습니다.

@Test
void generateObjectsList() {
    EasyRandom generator = new EasyRandom();

  //Generamos una lista de 5 Personas
    List<Person> persons = generator.objects(Person.class, 5)
        .collect(Collectors.toList());

    assertEquals(5, persons.size());
}

 

 

이 테스트는 그 자체로는 그다지 유용하지 않습니다. 단순히 데이터를 데이터베이스에 덤프하는 데 사용될 수 있는 목록을 생성하는 능력을 보여주기 위한 것입니다.

 

 

매개변수화된 데이터 생성

이제 이 라이브러리를 사용하여 개체 자체를 생성할 때 보다 정확한 제어를 할 수 있는 방법을 알아보겠습니다. 매개 변수화를 통해 이 작업을 수행할 수 있습니다.

필드 값을 설정합니다. 테스트를 위해 특정 값(ID, 이름, 주소 등)을 일정하게 유지하고 싶다고 가정해 보겠습니다. 이를 위해서는 "EasyRandomParameters"를 사용하여 개체의 초기화를 구성하고 개체의 이름으로 매개 변수를 찾아야 합니다.

다음 방법을 알아보겠습니다:

EasyRandomParameters params = new EasyRandomParameters();

// Asignar un valor al campo por medio de una función lamba
params.randomize(named("age"),()-> 5);

EasyRandom easyRandom = new EasyRandom(params);

// El objeto tendrá siempre una edad de 5
Person person = easyRandom.nextObject(Person.class);

 

 

물론 컬렉션이나 복잡한 물체도 마찬가지일 수 있습니다.

클래스 Person이 내부에 주소 클래스를 포함하고 또한 두 사람의 목록을 생성하려고 한다고 가정합니다.

좀 더 완벽한 예를 보겠습니다:

EasyRandomParameters parameters = new EasyRandomParameters()
                .randomize(Address.class, () -> new Address("Random St.", "Random City"))

EasyRandom easyRandom = new EasyRandom(parameters);
return Arrays.asList(
        easyRandom.nextObject(Person.class),
        easyRandom.nextObject(Person.class)
);

 

 

이제 한 사람이 여러 개의 주소를 가질 수 있다고 가정해 보겠습니다. 이것은 "주소" 필드가 "사용자" 클래스 내의 목록이 된다는 것을 의미합니다.

이 라이브러리를 사용하면 컬렉션의 크기를 가변적으로 만들 수 있습니다. 매개 변수를 사용하여 이것을 수행할 수도 있습니다.

EasyRandomParameters parameters = new EasyRandomParameters()
               .randomize(Address.class, () -> new Address("Random St.", "Random City"))
    .collectionSizeRange(2, 10); 

EasyRandom easyRandom = new EasyRandom(parameters);

// El objeto tendrá una lista de entre 2 y 10 direcciones
Person person = easyRandom.nextObject(Person.class);

 

 

유사 랜덤 필드 설정

앞에서 보았듯이, 값을 설정하는 것은 매우 간단하고 간단합니다. 하지만 만약 우리가 데이터의 임의성을 통제하고자 한다면 어떨까요? 우리는 연결되지 않은 문자들의 문자열이 아니라 사람들의 임의 이름을 생성하고자 합니다. 이와 같은 필요성은 아마도 우리가 이메일, 전화번호, ID 번호, 카드번호, 도시 이름 등과 같은 분야에서 임의성을 갖는 것에 관심이 있을 때 더 명확할 것입니다.

이를 위해 다른 데이터 생성 라이브러리를 활용하는 것이 유용합니다. 페이커는 잘 알려진 것 중 하나입니다.

두 라이브러리를 결합하면 다음과 같은 코드를 얻을 수 있습니다:

EasyRandomParameters params = new EasyRandomParameters();
//Generar número entre 0 y 17
params.randomize(named("age"), () -> Faker.instance().number().numberBetween(0, 17));

// Generar nombre "reales" aleatorios
params.randomize(named("name"), () -> Faker.instance().name().fullName());

EasyRandom easyRandom = new EasyRandom(params);

Person person = easyRandom.nextObject(Person.class);

 

 

개체의 생성을 제어할 수 있는 다양한 매개 변수가 있습니다.

 

 

클로징

이지랜덤(EasyRandom)은 단위 테스트를 유지하는 데 도움이 되기 때문에 단위 테스트를 개발한다면 배낭의 일부가 되어야 하는 도서관입니다. 게다가, 비록 이상하게 보일지라도, 테스트에서 일부 통제된 무작위성을 확립하는 것은 나쁜 일이 아닐 수도 있습니다. 어떤 면에서는, 새로운 테스트 케이스를 자동으로 생성하는 방법이고 코드에서 버그를 발견할 확률을 높일 것입니다.

반응형