프로그래머스 데브코스 20250125
- 명언 게시판을 TDD로 구현
- Service Controller Repository 분리
명언게시판 TDD - 수업
명언 게시판을 TDD로 구현
요구사항
- 명언 게시판을 만들어라
- 명언을 등록할 수 있다.
- 명언을 조회할 수 있다.
- 명언을 수정할 수 있다.
- 명언을 삭제할 수 있다.
- assertThat 의존성 : testImplementation("org.assertj:assertj-core:3.26.3")
TDD란
- TDD(Test Driven Development)는 테스트 주도 개발이라고 하며, 테스트를 먼저 작성하고 그 테스트를 통과하는 코드를 작성하는 개발 방법론이다.
- RGB
- r 실패하는 테스트 케이스
- 만들고 싶은 기능을 점검할 테스트 코드를 작성한다. 이때, 아직 기능 코드를 구현하지 않았으므로 테스트 결과는 실패로 반환된다. 실패하는 테스트를 가장 빠르게 구현하는 방법은 아무 값이나 반환하도록 하는 것이다.
- g 테스트를 통과하는 코드 작성(최소한의 코드 해결, 꼼수를 부려도 됨)
- 테스트 코드를 만족시킬 수 있는 기능을 구현한다. 테스트 통과를 최우선으로 생각하며 작업한다. 즉 단위 테스트를 통과할 수 있을 정도의 최소한의 코드만 작성한다.
- b 리팩토링 할게 있으면 다시 리팩토링
- 기능의 성능이 향상되며, 재사용성이 좋고, 가독성이 좋은 코드로 기능 코드를 개선한다. 테스트 코드를 통해 다시 기능 코드를 점검한다. → 기능 테스트가 완전해질 때까지 2, 3의 과정을 반복한다.
- r 실패하는 테스트 케이스
- TDD는 기본적으로 위 3단계의 반복으로 진행하며 점진적으로 개발이 진행된다
TDD의 장점
객체 지향적인 코드 개발
TDD는 코드의 재사용 보장을 명시하므로 TDD를 통한 소프트웨어 개발 시 기능별로 모듈화가 이루어진다. 이는 의존성과 종속성이 낮은 모듈로 조합된 소프트웨어 개발을 가능하게 하며, 필요에 따라 모듈을 추가하거나 제거해도 소프트웨어 전체 구조에 영향을 미치지 않게 된다.
설계 수정시간의 단축
테스트코드를 먼저 작성하기 때문에 최초 설계안을 만족하게 하며 입출력 구조와 기능의 정의를 명확하게 하게 되므로 설계의 구조적 문제를 바로 찾아낼 수 있다.
유지보수(리팩토링)의 용이성
기본적으로 단위 테스트 기반의 테스트 코드를 작성하기 때문에 추후 문제가 발생하였을 때 각각의 모듈별로 테스트를 진행해보면 문제의 지점을 쉽게 찾을 수 있다.
테스트 문서의 대체 가능
대부분의 개발 프로젝트에서 테스트를 진행하는 경우 단순 통합 테스트에 지나지 않는다. TDD를 하게 될 때 테스팅을 자동화시킴과 동시에 더욱 정확한 테스트 근거를 산출해 정의서를 작성할 수 있다.
TDD의 단점
생산성 저하
프로젝트를 진행할 때 경험 때문에 어떤 예외상황이 발생할지 눈에 뻔히 보이는 경우가 종종 있다. 이러한 단발성 개발은 개발 기간이 타이트하게 잡히는 경우가 많은데, 이럴 때 TDD를 이용해 테스트 코드를 작성하고 그에 통과하기 위한 코드를 작성한다면 비효율적일 것이다.
사전준비 기간
TDD를 프로젝트에 도입하려면 사전에 필요한 지식을 습득하고 개발 환경을 구축해야 한다. TDD를 효과적으로 사용할 수 있는 수준으로 개발자를 교육하는 데 보통 1~6개월간의 시간이 필요하다.
좋은 TDD의 특징 (FIRST 규칙)
Fast
테스트는 빠르게 동작하여 자주 돌릴 수 있어야 한다.
Independent
각각의 테스트는 독립적이며 서로 의존해서는 안 된다.
Repeatable
어느 환경에서도 반복할 수 있어야 한다.
Self-Validating
테스트는 성공 또는 실패로 bool 값으로 결과를 내어 자체적으로 검증되어야 한다.
Timely
테스트는 적시에 즉, 테스트하려는 실제 코드를 구현하기 직전에 구현해야 한다.
참조 TDD
java TDD
- JUnit
- JUnit은 자바 프로그래밍 언어용 단위 테스트 프레임워크이다. JUnit은 Kent Beck과 Erich Gamma가 만들었으며, Beck는 JUnit을 사용하여 익스트림 프로그래밍을 홍보했다. JUnit은 테스트 주도 개발(TDD)의 일환으로 사용된다.
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestClass {
@Test
public void testMethod() {
assertEquals(1, 1);
}
@Test
public void testMethod2() {
assertThat(1).isEqualTo(1);
}
// 순서 확인 테스트
@Test
public void testMethod3() {
assertThat("가나").containsSequence("가", "나");
}
}
Service Controller Repository
- Service: 비즈니스 로직을 처리하는 클래스
- Controller: 클라이언트의 요청을 받아서 응답을 반환하는 클래스
- Repository: 데이터베이스에 접근하는 클래스
Stream
명령형 VS 선언형
- 명령형: 어떻게 할 것인가를 명시
- ex) for문, if문
- 단점 : 실수할 확률이 높다.
- 코드가 복잡해지면 의도가 불분명해진다.
- 장점: 직관적, 자유도가 높다
- 선언형: 무엇을 할 것인가를 명시
- ex) stream, lambda
- 단점: 직관적이지 않다.
- 장점: 실수할 확률이 낮다.
- 코드가 간결해진다.
- 람다 => 익명함수
- 기본은 람다를 쓰되,
람다 안에서 사용하는게 재사용성이 높거나, 가독성이 떨어지는 복잡한 코드일 경우 함수 정의
- 기본은 람다를 쓰되,
- java stream은 원본의 불변성을 보장한다.
- int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // arr의 값에서 각각 2배된 배열 만들기 int[] arr2 = Arrays.stream(arr).map(i -> i * 2).toArray();
method reference
- 람다식을 더 간결하게 표현하는 방법
- 클래스::메소드
EX)
Function<String, Integer> f = Integer::parseInt;
Arrays.stream(arr).forEach(System.out::println)
Stream
java.util.stream 패키지에는 BaseStream과 이를 부모로 삼는 자식 인터페이스인
Stream, IntStream, LongStream, DoubleStream이 존재한다.
Optional / npe
Optional :
null이 올 수 있는 값을 감싸는 Wrapper 클래스로, 참조하더라도 NPE가 발생하지 않도록 도와준다.
- Optional은 메소드의 결과가 null이 될 수 있으며, null에 의해 오류가 발생할 가능성이 매우 높을 때 반환값으로만 사용된다.
- Stream API와 결합되어 유연한 체이닝 api를 만들기 위해 탄생
- 단점:
- NullPointerException 대신 NoSuchElementException가 발생함
- 이전에는 없었던 새로운 문제들이 발생함
- 코드의 가독성을 떨어뜨림
- 시간적, 공간적 비용(또는 오버헤드)이 증가함
NPE :
NullPointerException null 값으로 인한 예외
- Optional은 메소드의 결과가 null이 될 수 있으며, null에 의해 오류가 발생할 가능성이 매우 높을 때 반환값으로만 사용
'프로그래머스 데브코스' 카테고리의 다른 글
TIL - Cascade, LazyLoding, Autowired, JPA Naming Methods, 페이징 (0) | 2025.01.22 |
---|---|
데프코스 TIL - DTO, DIP (0) | 2025.01.08 |
데브코스 TIL - Map, StringBuilder, lombok, Files (0) | 2025.01.07 |