본문 바로가기

Test Code9

테스트를 위해 정의했던 Public 메서드 테스트를 위해 정의했던 Public 메서드 Service 레이어에 대한 테스트 코드를 작성을 위해 Mockito 라이브러리를 활용했다. 협력 객체인 Repository 레이어에 대한 Stubbing을 진행했는데, 실제 데이터베이스에서 저장된 후 반환되는 것이 아니기 때문에 실제 저장되어 있던 것처럼 구성을 해야했다. 이때, 주로 고민이 된던 것은 'Entity에 id는 어떻게 설정해줘야 하는 것인가?' 였다. 누구나 고민이 되는 내용이지 않을까.. 싶다. 아래는 게시글을 저장할 때, 필수로 포함되어야하는 카테고리 Entity 이다. // Category.java @Entity public class Category { @Id @GeneratedValue(strategy = GenerationType.ID.. 2024. 2. 13.
테스트 격리: 인수 테스트에서 사용했던 방법 테스트 격리 현재 ATDD, 클린 코드 with Spring 8기에 참가해서, 미션을 진행 중이다. E2E(API) 테스트 기반의 인수 테스트를 작성해야 하기 때문에, '데이터베이스와의 격리를 어떠한 방법으로 할 것인가?' 를 고민을 해봐야 했다. 하지만, 나는 요구사항을 분석하고 인수 테스트를 작성하는 프로세스를 익히는 데만 급급한 나머지 비교적 간단한 @DirtiesContext 를 사용했다. 나도 테스트 실행속도가 너무 느려서 답답했는데, 리뷰어님께서 마지막 단계에서 아래와 같이 조언을 해주셨다. 따라서, 공부한 내용을 이번 기회에 제대로 정리해보고자 한다. 테스트 격리가 왜 필요할까? 우선, 격리가 왜 필요한지부터 생각해보자. 가령, 아래 두 테스트는 독립적으로 진행되어야 하고 테스트 간에 간섭이.. 2024. 2. 9.
Test Double 이란? Test Double 이란? 테스트를 목적으로 Real Object를 흉내내는 모든 대역 객체를 통틀어 Test Double이라고 합니다. 또한, 테스트 대역은 Dummy, Stub, Spy, Mock, Fake로 나눠집니다. Test Double의 필요성 테스트 하려는 객체가 여러 객체들 혹은 의존성(데이터베이스, 메일 등)으로 묶여있을 때, 테스트를 하기 위해서는 대역이 필요하게 됩니다. 테스트 수행 시 외부 의존성에 영향을 주면 안되는 경우 테스트 수행 시 외부 의존성의 응답을 원하는 응답으로 만들어야 하는 경우 Test Double의 종류 Dummy 실제 사용되지는(호출되지는) 않는 객체 주로 메서드 시그니처를 맞추기 위해 사용 public class DummyLogger implements Lo.. 2023. 11. 7.
콘솔 기반 UI 테스트를 어떻게 해야할까? 콘솔 기반 UI 테스트를 하게 된 계기 이전까지 상태 값을 가지는 도메인 클래스를 구현할 때 TDD로 구현을 해서 깔끔하게 잘 해왔다고 생각한다. 다만, UI 로직에 대해서는 고민만 했을 뿐… '굳이..?' 라는 생각에 지금까지 제대로 된 테스트를 하지 않았다. 최근, 취업을 위해 사전과제를 진행했었다. 해당 과제는, csv 파일(key-value 형태)을 읽어서 사용자로부터 입력받은 key 값에 해당하는 value를 출력하는 내용이었다. 이 또한 상태 값을 가지는 도메인 클래스를 구현할 때는 비교적 깔끔하게 잘 해왔다고 생각하지만, UI 로직에 대해서는 수동적으로 테스트를 하고 제출했었다. 시간적 여유가 없어서, 제출했지만.. 근래 UI 로직에 대한 테스트를 못한 것에 대한 아쉬움이 남아서 '어떻게 테.. 2023. 10. 20.
[JUnit] 테스트하기 어려운 코드를 테스트 하기 쉬운 코드로 테스트하기 어려운 코드 package racing; public class Car { private static final int FORWARD_NUM = 4; private static final int MAX_BOUND = 10; private String name; private int position; public void move() { if( getRandomNo() >= FORWARD_NUM) this.position++; } private int getRandomNo() { Random random = new Random(); return random.nextInt(MAX_BOUND); } //생략.. } Car 라는 클래스는 Car의 이름을 의미하는 멤버변수 'name'과 Car의 위치를.. 2023. 4. 22.
[JUnit] AssertJ 라이브러리의 문자열 테스트와 숫자 테스트의 메서드 라이브러리 의존성 설정 Java8 이상 기반 프로젝트는 3.x 버전을, Java7 이하 기반 프로젝트는 2.x 버전을 사용해야 한다. Gradle testCompile 'org.assertj:assertj-core:3.6.2' Maven org.assertj assertj-core 3.6.2 test 테스트 대상 지정 모든 테스트 코드는 assertThat() 메서드에서 출발하며, 다양한 메서드를 연쇄 호출해서 코드를 작성함. assertThat(테스트 타켓).메소드1().메소드2().메소드3(); 문자열 테스트 assertThat("Hello, world! Nice to meet you.") // 주어진 "Hello, world! Nice to meet you."라는 문자열은 .isNotEmpty() .. 2023. 4. 14.
[JUnit] 스트림(Stream)을 이용한 JUnit기반 테스트 코드 작성 도메인 모델 사람의 속성인 이름과 나이를 멤버 변수로 가지는도메인 모델이다. public class Person { private String name; private int age; public Person( String name, int age ) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } 요구사항 충족하는 테스트 코드를 작성 사람들 중에 성인(나이가 26.. 2023. 4. 14.
[JUnit] assertj 활용한 테스트 코드 작성 해당 글은 NEXTSTEP 자바 플레이그라운드 with TDD, 클린 코드를 통해서 새롭게 배우고 내용을 기록한 글입니다. contains(String values) 배열로 반환하는 값의 경우 assertj의 contains()를 활용해 반환 값이 맞는지 검증 @Test void split1() { String actual = "1,2"; String[] actualSplit = actual.split(","); assertThat(actualSplit).contains("1"); assertThat(actualSplit).contains("2"); } containsExactly(String values) 배열로 반환하는 값의 경우 assertj의 containsExactly()를 활용해 반환 값이 맞.. 2023. 4. 12.
[Java] JUnit을 이용한 테스트 및 리팩토링 리팩토링(Refactoring)? 현재까지 대부분의 애플리케이션 구현과정을 돌이켜보면 요구사항을 만족하는 코드를 구현하면 개발을 완료했었다. 하지만 요구사항을 만족하는 코드를 구현했다고 개발이 완료된 것이 아니다. 소스코드를 구현했으면 반드시 뒤따라야 하는 과정이 중복을 제거하고, 읽기 좋은 코드를 구현하기 위해 구조를 변경하는 리팩토링이다. 리팩토링이란 소스코드의 가독성을 높이고 유지보수를 편하게 하기 위해 소스코드의 구조를 변경하는 것을 의미한다. 따라서, 아래와 같은 요구사항에 맞춰서 리팩토링을 진행해보자. 메서드가 한가지 책임만 가지도록 구현하자. 인덱트(indent, 들여쓰기) 깊이를 1단계로 유지하자. 인덴트는 while 문과 if문을 사용할 경우 인덴트 깊이가 1씩 증가한다. 예를 들면, 아.. 2023. 3. 2.