6 minute read

test 코드 작성

  • 작성자, 제목, 내용으로 검색 가능하도록 테스트 했다.
  • 게시글 목록 조회했던 코드에 추가로 작업을 했다.
@Test
public void findAllTest() {
	List<Board> list = null;

	// 작성자, 제목, 내용으로 검색 가능하도록 테스트
	String writer = "adm";
	String title = null;
	String content = null;

	// service에서 문자열 3개의 매개값을 받을 수 있도록 작성
	list = service.findAll(writer, title, content);

	assertThat(list).isNotNull();
}

service 코드 작성

  • 기존의 findAll() 메서드는 매개값이 없었기 때문에 추가해준다.
// 매개값 추가
public List<Board> findAll(String writer, String title, String content) {
	List<Board> list = null;
	SqlSession session = getSession();
	
	// dao에도 추가해서 같이 넘겨주기
	list = dao.findAll(session, writer, title, content);
	
	session.close();
	
	return list;
}

dao 코드 작성

  • dao에서도 마찬가지로 매개값 추가해주기
public List<Board> findAll(SqlSession session, String writer, String title, String content) {
	return session.selectList("boardMapper.selectAll", writer);
}

mapper 코드 작성

  • 작성자(writer)가 ‘adm’으로 시작할 때 조회되도록 수정
<select id="selectAll" resultMap="boardListResultMap">
	SELECT  B.NO, 
			B.TITLE, 
			M.ID, 
			B.READCOUNT, 
			B.ORIGINAL_FILENAME, 
			B.RENAMED_FILENAME, 
			B.CONTENT, 
			B.CREATE_DATE, 
			B.MODIFY_DATE
	FROM BOARD B
	JOIN MEMBER M ON(B.WRITER_NO = M.NO)
	WHERE B.STATUS = 'Y'
			<!-- 작성자 검색 추가 -->
			AND M.ID LIKE '%' || #{writer} || '%'
</select>

오라클 연산자 오랜만이라 기억이 가물가물.

  • LIKE : 특정 문자열 포함
  •   : 연결 연산자

이렇게 테스트를 돌려보면 ‘admin1’, ‘admin2’ 사용자가 작성한 게시글이 모두 조회된다.


여러 개의 값 넘기기 - dao 코드 작성

  • 두번째 매개값을 map으로 설정하면 쿼리문에서는 map에 있는 writer, title, content를 꺼내서 실행
public List<Board> findAll(SqlSession session, String writer, String title, String content) {
	// 여러 개의 값을 담을 수 있도록 map(Collenction) 생성
	Map<String, String> map = new HashMap<>();
	
	// 생성한 map에 값 담아주기
	map.put("writer", writer);
	map.put("title", title);
	map.put("content", content);
	
	// 넘겨주는 값도 하나의 값(writer, title, content)이 아닌 map으로 지정
	return session.selectList("boardMapper.selectAll", map);
}

여기까지 작성하고 아래처럼 test 코드에서 모두 null을 할당할 경우에는 모든 게시글을 조회한다.
쿼리문이 제대로 동작하지 않는 거라고 하셨는데 왜 그러는 걸까?;;

String writer = null;
String title = null;
String content = null;

모두 null이면 빈 리스트만 가져오니까 테스트는 통과하고 조회되는 목록은 없어야 되는 거 아닌가?ㅠㅠ
욕 나오네..
데이터를 한 눈에 볼 수 없다고 그냥 설명은….. 건너 뛴….
설명 해줘야되는 거 아니냐..


동적 SQL 추가 - if

  • 작성자가 null이 아닐 경우 실행할 쿼리문 추가
String writer = "adm";
String title = null;
String content = null;

다시 test 코드에서 작성자의 id 추가

-

<!-- parameterType="map" 추가 -->
<select id="selectAll" parameterType="map" resultMap="boardListResultMap">
	SELECT  B.NO, 
			B.TITLE, 
			M.ID, 
			B.READCOUNT, 
			B.ORIGINAL_FILENAME, 
			B.RENAMED_FILENAME, 
			B.CONTENT, 
			B.CREATE_DATE, 
			B.MODIFY_DATE
	FROM BOARD B
	JOIN MEMBER M ON(B.WRITER_NO = M.NO)
	WHERE B.STATUS = 'Y'
	
	<!-- 작성자가 null이 아닐 때 실행할 쿼리문 추가 -->
	<if test="writer != null">
		AND M.ID LIKE '%' || #{writer} || '%'
	</if>
</select>

mapper.xml 파일에 동적 쿼리도 추가.


동적 SQL - 다중 if

// 작성자로 검색
String writer = "adm";
String title = null;
String content = null;

// 제목으로 검색
String writer = null;
String title = "안녕하세요";
String content = null;

// 내용으로 검색
String writer = null;
String title = null;
String content = "내용입";

테스트 코드에서 작성자, 제목, 내용을 각각 넣어주고 따로따로 테스트 했다.

-

<select id="selectAll" parameterType="map" resultMap="boardListResultMap">
	SELECT  B.NO, 
			B.TITLE, 
			M.ID, 
			B.READCOUNT, 
			B.ORIGINAL_FILENAME, 
			B.RENAMED_FILENAME, 
			B.CONTENT, 
			B.CREATE_DATE, 
			B.MODIFY_DATE
	FROM BOARD B
	JOIN MEMBER M ON(B.WRITER_NO = M.NO)
	WHERE B.STATUS = 'Y'
	
	<!-- 다중 if문 추가 -->
	<if test="writer != null">
		AND M.ID LIKE '%' || #{writer} || '%'
	</if>
	<if test="title != null">
		AND B.TITLE LIKE '%' || #{title} || '%'
	</if>
	<if test="content != null">
		AND B.CONTENT LIKE '%' || #{content} || '%'
	</if>
</select>

위의 테스트 코드를 작성자, 제목, 내용의 값이 각자 들어있을 경우(3번)을 모두 테스트 했다.
이건 오히려 수업 때는 쉽네~~~ 했는데 다시 들으니까 더 모르겠다. 설명이 진짜 왜저래…


동적 SQL - where / 다중 if

  • where : 태그 안에 AND나 OR로 시작할 경우 AND, OR 제거
<select id="selectAll" parameterType="map" resultMap="boardListResultMap">
	SELECT  B.NO, 
			B.TITLE, 
			M.ID, 
			B.READCOUNT, 
			B.ORIGINAL_FILENAME, 
			B.RENAMED_FILENAME, 
			B.CONTENT, 
			B.CREATE_DATE, 
			B.MODIFY_DATE
	FROM BOARD B 
	JOIN MEMBER M ON(B.WRITER_NO = M.NO) 

	<!-- where / 다중 if 추가 -->
	<where>
		<if test="writer != null">
			M.ID LIKE '%' || #{writer} || '%' 
		</if>
		<if test="title != null">
			AND B.TITLE LIKE '%' || #{title} || '%' 
		</if>
		<if test="content != null">
			AND B.CONTENT LIKE '%' || #{content} || '%' 
		</if>
		AND B.STATUS = 'Y'
	</where>
</select>

각 구문을 사용했을 때 실제 쿼리문이 어떻게 만들어지는지 잘 생각해야할 거 같다.
where구문은 태그 안의 AND나 OR를 제거하기 때문에 신텍스 에러가 나지 않는다.
만약 첫번째 if문이 만족하지 않을 경우 두번째로 넘어가는데
이때 쿼리문은 ‘WHERE AND 블라블라’ 이렇게 된다. 이건 신텍스 에러기 때문에 AND나 OR로 시작할 경우 AND, OR를 제거해주는 where절을 사용한다.

-

작성자, 제목, 내용 모두 null

String writer = null;
String title = null;
String content = null;

이렇게 작성하고 테스트할 경우 통과.
모든 게시글이 조회된다.
다중 if문을 모두 만족하지 않을 경우

AND B.STATUS = 'Y'

마지막 where절을 수행하기 때문에.


동정 SQL - trim / 다중 if

  • trim : 쿼리문에서 특정 문자열 제거
<select id="selectAll" parameterType="map" resultMap="boardListResultMap">
	SELECT  B.NO, 
		B.TITLE, 
		M.ID, 
		B.READCOUNT, 
		B.ORIGINAL_FILENAME, 
		B.RENAMED_FILENAME, 
		B.CONTENT, 
		B.CREATE_DATE, 
		B.MODIFY_DATE
	FROM BOARD B 
	JOIN MEMBER M ON(B.WRITER_NO = M.NO) 

	<!-- trim / 다중 if문 추가 -->
	<trim prefix="WHERE" prefixOverrides="AND|OR"> 
		<!-- where절에서 AND나 OR 문자 제거 -->
		<if test="writer != null">
			M.ID LIKE '%' || #{writer} || '%' 
			<!-- 첫번째 if문에서 AND가 있어도 상관 없지만 굳이? 라고 하셨음 -->
			<!-- ADN M.ID LIKE '%' || #{writer} || '%'  -->
		</if>
		<if test="title != null">
			AND B.TITLE LIKE '%' || #{title} || '%' 
		</if>
		<if test="content != null">
			AND B.CONTENT LIKE '%' || #{content} || '%' 
		</if>
		AND B.STATUS = 'Y'
	</trim>
</select>

여기서는 prefixOverrides로 지정한 문자 AND, OR가 삭제된다.


동적 SQL - choose / when / otherwise

  • choose문에서는 만족하는 when구문의 쿼리만 실항하기 때문에 문자열 제거 불필요
  • 만족하는 when구문이 없을 경우 otherwise에 작성한 쿼리문 실행
<select id="selectAll" parameterType="map" resultMap="boardListResultMap">
	SELECT  B.NO, 
			B.TITLE, 
			M.ID, 
			B.READCOUNT, 
			B.ORIGINAL_FILENAME, 
			B.RENAMED_FILENAME, 
			B.CONTENT, 
			B.TYPE,
			B.CREATE_DATE, 
			B.MODIFY_DATE
	FROM BOARD B
	JOIN MEMBER M ON(B.WRITER_NO = M.NO)

	<!-- choose / when / otherwise 추가 -->
	<choose>
		<when test="writer != null">
			AND M.ID LIKE '%' || #{ writer } || '%'
		</when>
		<when test="title != null">
			AND B.TITLE LIKE '%' || #{ title } || '%'
		</when>
		<when test="content != null">
			AND B.CONTENT LIKE '%' || #{ content } || '%'
		</when>
		<!-- otherwise 생략 가능
		<otherwise>
			위 조건을 모두 만족하지 않을 경우 실항할 쿼리문 작성
		</otherwise>
		-->
	</choose>
</select>

Sql 조각 생성

  • 공통으로 사용한 쿼리문 지정하기
<sql id="boardListSql">
	SELECT  B.NO, 
			B.TITLE, 
			M.ID, 
			B.READCOUNT, 
			B.ORIGINAL_FILENAME, 
			B.RENAMED_FILENAME, 
			B.CONTENT, 
			B.TYPE,
			B.CREATE_DATE, 
			B.MODIFY_DATE
	FROM BOARD B
	JOIN MEMBER M ON(B.WRITER_NO = M.NO)
	WHERE B.STATUS = 'Y'
</sql>

-

<select id="selectAll" parameterType="map" resultMap="boardListResultMap">
	<!-- sql 조각 추가 -->
	<include refid="boardListSql" />

	<choose>
		<when test="writer != null">
			AND M.ID LIKE '%' || #{ writer } || '%'
		</when>
		<when test="title != null">
			AND B.TITLE LIKE '%' || #{ title } || '%'
		</when>
		<when test="content != null">
			AND B.CONTENT LIKE '%' || #{ content } || '%'
		</when>
		<!-- 
		<otherwise>
			위 조건을 모두 만족하지 않을 경우 실항할 쿼리문 작성
		</otherwise>
		-->
	</choose>
</select>

앞서 배운 sql 조각과 동적 SQL문을 결합하여 작성한 쿼리문이다.
sql 조각을 사용함으로써 재사용이 가능하고 간결한 코드 작성도 가능해졌다.


@ParameterrizedTest / @CsvSource 어노테이션 사용

  • 여러 값을 넣어 테스트 가능하도록 사용
  • nullValues
    • null을 작성할 경우 문자열로 인식하기 때문에 null 타입으로 지정
      • NullPointException 오류로 테스트 통과 불가 > 테스트가 잘 되고 있는 거임!!
@ParameterizedTest
@CsvSource(
	value = {
		"adm, null, null", // 작성자로 검색
		"null, 안녕하세요, null", // 제목으로 검색
		"null, null, 내용입", // 내용으로 검색
		"null, null, null" // 모두 null일 경우
	},
	nullValues = "null"
)
@DisplayName("게시글 전체 목록 조회 - 검색 기능 포함") // 테스트명도 변경해줬다.
public void findAllTest(String writer, String title, String content) {
	List<Board> list = null;
	
	list = service.findAll(writer, title, content);
	
	assertThat(list.size()).isPositive().isEqualTo(expected);
}

위에서 3번이나 주석 처리했다가 풀었다 하면서 테스트했던 것을
@ParameterrizedTest / @CsvSource 어노테이션을 사용하여 한 번에 테스트가 가능하도록 작성했다.


이것도 계속 리팩토링이 진행됐다. 머리가 복잡하다..
앞에서 완전 이해되었다! 했던 것도 다시 헷갈리기 시작네.ㅠㅠ 처음부터 다시 해보쟝..


Categories:

Updated: