3 minute read

TDD

  • Test Driven Development
  • 테스트 주도 개발
  • TDD 이 블로그에 많은 정보가 있다. 아직은 무슨 말인지 잘 모르겠다.
  • 설계 > 테스트 코드 작성 > 구현 코드 작성
    • 기존) 설계 > 구현 코드 작성 > 테스트 진행

Alt text

테스트 코드는 여기에 작성한다.


jUnit

  • Java 단위 테스트 프레임워크

Alt text

프로젝트 우클릭 하고 해당 메뉴를 클릭하면 테스트가 가능하다.

-

Alt text

테스트 코드가 잘 수행 되면 초록색, 반대일 경우 빨간색으로 표시된다.

<!-- pom.xml -->

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.8.2</version>
    <scope>test</scope>
</dependency>

전에 pom.xml 파일에 추가했던 jUnit 라이브러리를 이 때 사용하는 거였네.


현재 프로젝트가 테스트가 가능한 환경인지 확인

@Test
public void nothing() {
	// 아무 내용 없음
}

sqlSession 생성 테스트

@Test
@DisplayName("SqlSession 생성 테스트")
public void create() {
	assertNotNull(session);
}

Annotation

  • @Test : test
  • @DisplayName : 테스트명 지정
  • @Disabled : test에서 제외
    • 실습 때는 테스트 가능한 환경인지 제일 처음에만 확인했고, 다음 테스트 진행 시에는 필요 없기 때문에 이 어노테이션을 지정했다.
    • 아예 삭제하지않고 어노테이션을 사용한 이유는 다른 작업자도 다른 환경에서 이 코드를 사용할 수 있기 때문에
  • @BeforeAll : 테스트 메서드가 실행되기 전에 한 번만 실행
  • @BeforeEach : 각 테스트 메서드가 실행되기 전에 무조건 실행

MemberSevice / MemberServiceTest 생성 및 작성

  • com.kh.member.model.service 패키지 생성 후 MemberSerivce.java 파일 생성
  • 클래스명에 커서 올려놓고 Ctrl + 1 키를 누르면 아래와 같이 나오고 표시된 것을 클릭하면 test 폴더에 MemberServiceTest 파일이 자동으로 생성

Alt text

-

Alt text

패키지도 동일하게 test 파일이 생성되었다.


테스트 환경 확인

  • 일단 테스트가 가능한 환경인지 체크
  • 테스트 클래스에도 DisplayName 어노테이션 지정 가능
@DisplayName("Member Test") // 테이스명 지정
class MemberServiceTest {
	@Test
	@Disabled
	public void nothing() {
        // 테스트가 가능한 환경인지 확인
	}
}

AssertJ

  • 자바 JUnit의 테스트코드에 사용되어, 테스트코드의 가독성과 편의성을 높여 주는 라이브러리
import static org.assertj.core.api.Assertions.*;
import org.junit.jupiter.api.Test;

import.
AssertJ의 assertThatd() 메서드를 사용했다.


Service 객체 확인

import static org.assertj.core.api.Assertions.assertThat;

@DisplayName("Member Test")
class MemberServiceTest {
    // service 객체
	private MemberService service;
	
	@Test
	@Disabled
	public void nothing() {
	}
	
	@Test
	public void create() {
        // assertThat()을 이용하여 service 객체가 정상적으로 생성 되는지 확인
		assertThat(service).isNotNull();
	}
}

위 처럼 작성시 false이 뜨면서 test를 통과하지 못한다.
이유는 service에 값을 할당하지 않았기 때문에 null이 담겨 있다. isNotnull = null 아니다. null이 아닐 경우에만 test가 통과된다.

-

해결 방법은 service에 값 할당하기.
실습 때는 test가 실행될 때마다 service를 새로 생성하도록 했다.

@DisplayName("Member Test")
class MemberServiceTest {
	private MemberService service;
	
	@Test
	@Disabled
	public void nothing() {
	}

    // 각 테스트 메서드가 실행되기 전에 무조건 실행
    @BeforeEach
	public void setup() {
		// service 생성
		service = new MemberService();
	}
	
	@Test
	public void create() {
		assertThat(service).isNotNull();
	}
}

test 메서드를 실행하기 전에 service를 새로 생성했기 때문에
이제 jUnit 테스트를 돌리면 통과되어 초록색으로 표시된다.


회원수 조회 테스트

  • MemberServiceTest 파일에 테스트 메서드 생성
// MemberServiceTest

public void getMemberCountTest() {
	int count = service.getMemberCount();

	assertThat(count).isPositive().isGreaterThanOrEqualTo(2);
}

int 타입의 count 변수에 회원수를 담아준다.
그리고 assertTht()으로 확인한다.

  • isPositive() : 양수
  • isGreaterThanOrEqualTo(2) : count가 2보다 클 것이라고 예상
  • 처음엔 return 0; 으로 테스트 진행
    • count는 2보다 커야하기 때문에 테스트 통과 불가

-

// MemberService

public int getMemberCount() {
	int count = 0;
	SqlSession session = getSession(); // connection 객체라고 생각하면 됨
	
	count = dao.getMemberCount(session); // dao에 요청
	
	session.close();
	
	return count;

	// 위 코드 작성 전에 0으로 테스트 진행
	return 0;
}

MemberService에 test에서 사용했던 메서드도 생성해준다.

이렇게 테스트 코드를 작성한 뒤에..
테스트가 통과될 수 있게 비즈니스 코드를 리팩토링 한다고 한다..!
뭔지는 알겠지만 아직은 왜 이렇게 하는지 잘 이해는 안 되고..
적응도 안 된다.ㅎㅎ..
우리가 예측을 하면서 코딩한다고??

-

// MemberDao

public class MemberDao {
	public int getMemberCount(SqlSession session) {
		
		return 0;
	}
}

dao에서 return값을 service에 넘겨주고
service는 이걸 count 변수에 담아준다.
이건 servlet/JSP 수업 때 MVC2 패턴 사용했던 거랑 동일하다.

다른 건 SqlSession 객체를 사용하는 것.

-

// MemberDao
public class MemberDao {
	// 회원수 조회
	public int getMemberCount(SqlSession session) {
		return session.selectOne("memberMapper.selectCount");
	}

Dao 파일을 다시 이렇게 수정했다.
SqlSession 객체를 받아서 쿼리문을 연결해준다.
member-mapper에 있는 namespace가 memberMapper인 쿼리를 찾아 연결시켜준다.

<!-- member-mapper.xml -->

<mapper namespace="memberMapper"> <!-- namespace 일치하는 거 먼저 찾고 -->
	<select id="selectCount" resultType="_int"> <!-- 일치하는 id를 찾아서 -->
 		SELECT COUNT(*) FROM MEMBER <!-- 이 쿼리문을 실행시켜 준다!! -->
 	</select>
</mapper>

기존에 작성했던 Dao 코드랑은 좀 많이 다르다.
일단 쿼리문이 분리되기 때문에 코드가 많이 간결해졌다.
이게 mybatis의 장점인가봐요…!


SqlSession

  • 객체 하나를 조회하기 위해 SqlSession 객체의 selectOne() 메서드 사용
    • 첫번째 매개값은 쿼리문이 존재하는 경로(member-mapper의 namespace. 쿼리문의 ID)
    • mybatis-config에 지정한 mapper 파일만 가능
    • 두번째 매개값은 쿼리문에서 사용될 파라미터 객체
  • SqlSession 객체는 mybatis-cofig.xml 파일에 DB 연결 정보를 확인 후 등록된 mapper 중 연결된 것을 수행

오늘 수업은 일단 여기까지인데 세미하면서 이제야 servlet/JSP에 좀 익숙해졌나 했더니..
mapper 파일이 또 새로 생기다니.ㅋㅋㅋ 정신 똑바로 차려.


Categories:

Updated: