TDD(Test-driven development)
오늘 강의의 큰 맥락은 TDD였다. TDD란 테스트 주도 개발로써 매우 짧은 개발 사이클을 반복하는 소프트웨어 개발 프로세스이다.
요구사항을 검증하는 자동화 테스트 케이스를 작성한다. 그리고 테스트 케이스를 통과하기 위한 최소한의 코드를 작성한다. 마지막으로 작성한 코드를 리팩토링한다. 테스트 케이스 작성 - 코드 개발 - 리팩토링을 반복하면서 조금씩 조금씩 원하는 기능을 구현하는 것을 목표로 한다.
TDD를 이용했을 때의 장점은 아주 낮은 단계의 계단을 계속해서 올라감으로써 초보자가 보다 쉽게 접근할 수 있도록 해줄 수 있고, 개발 과정에서 생기는 오류를 찾는데 도움을 얻을 수 있다. 예를 들어 미로 찾기 프로그램을 만든다고 했을 때, 앞으로가기 구현 -> 회전 구현 -> 통행가능여부 확인 구현 -> 반복을 통한 길찾기 등 단계별로 테스트 케이스를 만들고 이를 구현하는 방법이다.
1. 자동화 테스트 작성을 위한 gradle 의존성 추가
testImplementation 'org.assertj:assertj-core:3.24.2'
2. 자동화 테스트 작성을 위한 import
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
3. 자동화 테스트 작성을 위한 입출력 설정
package com.ll;
import java.io.*;
import java.util.Scanner;
public class testUtil {
public static Scanner genScanner(String input) {
InputStream in = new ByteArrayInputStream(input.getBytes());
return new Scanner(in);
}
public static ByteArrayOutputStream setOutToByteArray() {
final ByteArrayOutputStream output = new ByteArrayOutputStream();
System.setOut(new PrintStream(output));
return output;
}
public static void clearSetOutToByteArray(ByteArrayOutputStream output) {
System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
try{
output.close();
}catch (IOException e){
throw new RuntimeException(e);
}
}
}
4. 사용 예시
package com.ll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayOutputStream;
import java.util.Scanner;
import static org.assertj.core.api.Assertions.assertThat;
public class AppTest {
@Test
@DisplayName("testutil genScanner 테스트")
void t1(){
Scanner scanner = testUtil.genScanner("""
문장1
문장2
문장3""".stripIndent());
String cmd = scanner.nextLine();
String content = scanner.nextLine();
String authorname = scanner.nextLine();
assertThat(cmd).isEqualTo("문장1");
assertThat(content).isEqualTo("문장2");
assertThat(authorname).isEqualTo("문장3");
}
@Test
@DisplayName("testutil.setOutToByteArray() 테스트")
void t2(){
ByteArrayOutputStream byteArrayOutputStream = testUtil.setOutToByteArray();
System.out.println("테스트 문장");
String out = byteArrayOutputStream.toString().trim();
assertThat(out).isEqualTo("테스트 문장");
testUtil.clearSetOutToByteArray(byteArrayOutputStream);
System.out.println("이제는 화면에 출력됩니다.");
}
}
Github flow
협업을 진행하기 위해 github에서 리포지토리를 공유하고 issue작성, branch 생성, branch protection rull 작성, PR(Pull Requests)요청하는 과정을 배웠다. 대단한 기술이 필요한 것은 아니지만 issue작성이나 branch 생성과 같은 일들은 간단하게 테스트 해보려고 해도 누구는 이렇게 쓰고 누구는 다르게 쓰고 하면서 branch들이 테스트를 시작하자마자 헷갈렸고 이슈의 제목과 작성 내용, 방법 등이 아직은 익숙하지 않았다. 많이 사용하면 보다 나아지리라 생각된다. 또한, 이슈를 작성하면서 프로젝트 관리자의 입장에서 문제해결, 기능 추가, 보수 등 생각할 꺼리들이 있어서 도움이 될 것 같다.
Git pull origin main // 메인 브랜치 최신화
git checkout -b e/1 // <- 브랜치명; 서브 브랜치 작성
//1번 E/1) 작업; 서브 브랜치 작업
Git add && git commit -m "작업" //2번 서브 브랜치 커밋
// 1번 2번 반복…
Git add && git commit -m "작업" //서브 브랜치 커밋
Git push origin e/1 // 서브 브랜치 푸쉬
// Github PR 생성(e/1 -> main)
// 투표
// 투표 통과
// merge
Git branch -d e/1 // E/1브랜치 삭제(반영완료된 브랜치)
Git fetch —prune // 혹시 모를 잔여(기록)데이터 삭제