새싹개발자 2020. 12. 14. 18:25

오늘은 정말 개인적으로 힘든 수업이었다. 오류가 계속해서 발생하고, 깃도 푸시가 안돼서 애를 먹었다ㅠ

 

오늘 수업은 JUnit 테스트! (JUnit테스트는 개발 시작 전 준비 단계이다.)

DB에 있는 데이터를 가져오기 위해서 어떤 과정이 필요할까? 

원래의 개발 단계는 아래와 같다.

jsp -> controller -> service -> dao -> mapper.xml -> DB(Mysql, Oracle)

 

자바단위테스트인 JUnit 테스트는 jsp, controller를 하기 전에 CRUD 테스트를 하기 위함이다.

JUnit -> service -> dao -> mapper.xml -> DB

 

톰캣/JUnit을 실행해야만 DB가 연동되는데, 톰캣이 종료되거나 JUnit 테스트가 끝나면 DB연동이 끊어진다.

테스트하기 전, 설정해야될 것들이 있다.

스프링 테스트 pom.xml에 dependency 의존성을 추가해준다.

의존성을 추가하기에 앞서, servlet버전을 2.5 -> 3.0.1로 변경해준다.(필수)

의존성추가 1. JDBC(Java DataBase Connection) 모듈 추가 후 설정 
의존성추가 2. Mysql 모듈 추가 설정
의존성추가 3. JDBC와 Mysql DB 중간에 쿼리를 사용하는 역할인 MyBatis 모듈 추가 후 설정

의존성1,2)

JDBC 모듈 추가 및 설정, Mysql 모듈 추가 및 설정을 통해 스프링에서 데이터베이스 커넥션 처리를 한다. 

-> DriverManagerDataSource (DB커넥션)

 

의존성3)

MyBatis 모듈 추가 및 설정으로 스프링에서 쿼리를 관리하는 처리를 한다. 

-> sqlSessionFactory (쿼리생성)

MyBatis에는 SELECT, INSERT, UPDATE, DELETE 쿼리를 수행하는 메소드들이 존재하는데 스프링에서 쿼리를 호출하는 메소드명(인터페이스)을 처리한다.

-> sqlSessionTemplate (쿼리호출)

 

DriverManagerDataSource - sqlSessionFactory - sqlSessionTemplate

 

JUnit 테스트 준비

src/test/java 패키지에 org.edu.test 패키지를 만들고, 그 안에 DataSourceTest.java 클래스를 만든다.

JUnit test case로 만든다. ( 그 중 JUnit 4 Test )

package org.edu.test;

import static org.junit.Assert.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

/**
 * JUnit 자바단위테스트이고, DataSource 지정 후 DB(Hsql, Mysql, Oracle) 접속,
 * 데이터베이스 테이블에 Create, Read, Update, Delete 테스트용 클래스
 * @author sieunlee
 *
 */
@RunWith (SpringJUnit4ClassRunner.class)
@ContextConfiguration (locations= {"file:src/main/webapp/WEB-INF/spring/**/*.xml"})
@WebAppConfiguration
public class DataSourceTest {

	@Test
	public void test() {
		//fail("Not yet implemented");
		System.out.println("JUnit테스트시작");
	}

}

@RunWith, @ContextConfiguration, @WebAppConfiguration 꼭 필요

pom.xml에 스프링 테스트 외부 모듈을 추가한다.

<!-- 스프링 Test사용 -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-test</artifactId>
  <version>${org.springframework-version}</version>
</dependency>

 

다음은 DB커넥션 테스트를 한다.

DB커넥션을 하기 위해서 pom.xml JDBC, Mysql 외부 모듈을 추가하고,  MyBatis를 사용하기 위한 외부 모듈을 추가한다.

<!-- jdbc 사용 -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-jdbc</artifactId>
  <version>${org.springframework-version}</version>
</dependency>

<!-- Mysql 데이터베이스 사용 -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.35</version>
</dependency>

<!-- 마이바티스 사용 --> 
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.2.8</version>
</dependency>
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>1.2.2</version>
</dependency>

root-context.xml로컬 mysql log4jdbc 설정 전 코드를 추가한다.

<!-- 로컬 mysql log4jdbc 설정전 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
  <property name="url" value="jdbc:mysql://127.0.0.1:3306/edu"></property>
  <property name="username" value="root"></property>
  <property name="password" value="apmsetup"></property>
</bean>

 

DataSourceTest.java 에 테스트 코드를 추가한다.

 

package org.edu.test;

import static org.junit.Assert.*;

import java.sql.Connection;
import java.sql.SQLException;

import javax.inject.Inject;
import javax.sql.DataSource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

/**
 * JUnit 자바단위테스트이고, DataSource 지정 후 DB(Hsql, Mysql, Oracle) 접속,
 * 데이터베이스 테이블에 Create, Read, Update, Delete 테스트용 클래스
 * @author sieunlee
 *
 */
@RunWith (SpringJUnit4ClassRunner.class)
@ContextConfiguration (locations= {"file:src/main/webapp/WEB-INF/spring/**/*.xml"})
@WebAppConfiguration
public class DataSourceTest {

	@Inject
	private DataSource dataSource; // 자바에서처럼 new 키워드로 객체 생성X, 스프링에서는 @Inject로 객체 생성	

	@Test
	public void dbConnectinoTest() throws SQLException {
		// 127.0.0.1의 3306포트에 있는 DB에 커넥션해서 사용가능한지 테스트
        
		// try-catch 구문은 테스트에서만 사용하고, 
		// 스프링에서는 throws Exception으로 예외를 스프링으로 보낸다.
		try {
			Connection connection = dataSource.getConnection();
			System.out.println("DB접속 성공");
		} catch (SQLException e) {
			System.out.println("DB접속 실패 원인 : "+ e);
			// e.printStackTrace();
		}
        
	}
}

 

 

다음은 쿼리에 관한 작업을 처리하기 위한 설정을 추가한다.

- sqlSessionFactory (쿼리생성)

root-context.xml 에 설정을 추가한다.

<!-- DataSource 설정으로 JDBC 연결후, MyBatis와 MySql을 연동시킴. 
SqlSessionFactory : myBatis와 스프링의 Connection 생성후 쿼리 위치지정.-->		 		
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">	   
  <property name="dataSource" ref="dataSource" />
  <!-- 매퍼 xml로만든 쿼리파일의 경로를 인식하게 함.(아래 classpath경로 src/main/resources/쿼리xml) -->
  <property name="mapperLocations" value="classpath:mappers/**/*Mapper.xml"></property>
</bean>

쿼리를 모아놓는 Mapper를 생성한다.

src/main/resources 패키지 안에 mappers 폴더 내에 memberMapper.xml 파일을 생성한다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<!-- 
memberMapper.xml : 회원관리에 대한 모든 쿼리를 모아서 관리하는 역할 -> MyBatis의 SessionFactory 클래스에서 쿼리를 생성한다.
이 쿼리를 호출할 때 사용하는 이름이 namespace 값이 된다.
이름이 memberMapper인 쿼리가 여러개 존재하게 되는데, 여러개를 구분해서 호출할 떄 사용하는 것이 id
 -->

<mapper namespace="memberMapper">
<!-- 아래 반환값이 MemberVO 클래스형이면, select*from 쿼리에서 결과값에 [자동 바인딩]된다. 
조건 : 단, 멤버클래스(MemberVO)의 멤버변수값이 tbl_member 테이블의 필드명과 일치하도록 만들어야 한다.
-->
<select id="selecMember" resultType="org.edu.vo.MemberVO">
select * from tbl_member
</select>

<!--
<insert id=""></insert>
<delete id=""></delete>
-->
</mapper> 

 

- sqlSessionTemplate (쿼리호출)

root-context.xml 에 설정을 추가한다.

<!-- 
  MyBatis에서 DAO를 이용하는 경우, SqlSessionTemplate라는 것을 이용해서 DAO를 구현함.
  DAO라는 것은 DataAccessObject 데이터핸들링(insert(),delete()등을 처리하는 클래스 DAO라고 합니다.
  개발자들이 직접 DB 연결, 종료작업하는 것을 줄여줌.
  sql세션템플릿을 호출할때 SqlSessionFactory를 생성자로 주입함.
-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" destroy-method="clearCache">
	<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
</bean>

 

DAO : Data Access Object-> DB의 data에 access하는 트랜잭션 객체

: DB를 사용해 데이터를 조작하는 기능을 전담하도록 만든 오브젝트

-> VO를 통해 DB의 데이터와 매칭되는 객체 생성 후 DB의 데이터를 조회, 삽입, 삭제, 갱신 가능

-> 사용자는 자신이 필요한 Interface를 DAO에게 던지고 DAO는 이 인터페이스를 구현한 객체를 사용자에게 편리하게 사용할 수 있도록 반환.

 

- MemberDAO 인터페이스에는 메소드를 선언만 해준다.

package org.edu.dao;

import java.util.List;

import org.edu.vo.MemberVO;

/**
 * 회원관리 DAO 메소드 명세(목차) 인터페이스
 * @author 이시은
 *
 */
public interface IF_MemberDAO {
	public List<MemberVO> selectMember() throws Exception;
    // selectMember() 는 MemberMapper.class에서 정의한 select쿼리 id
}

 

- MemberDAOImpl 로 인터페이스(IF_MemberDAO)를 구현해주고 필요한 메소드를 오버라이드하여 정의한다.

package org.edu.dao;

import java.util.List;

import javax.inject.Inject;

import org.apache.ibatis.session.SqlSession;
import org.edu.vo.MemberVO;
import org.springframework.stereotype.Repository;


// Service나 DAO라고 어노테이션명이 되어있는 것이 아니라 Repository는 어노테이션 사용

@Repository
public class MemberDAOImpl implements IF_MemberDAO {
	@Inject
	private SqlSession sqlSession;
	
	@Override
	public List<MemberVO> selectMember() throws Exception {
          // mapper.xml에 접근하는 방법(아래)
          return sqlSession.selectList("memberMapper.selectMember");
		
	}

}

 

tbl_member의 값 select 쿼리 테스트

package org.edu.test;

import static org.junit.Assert.*;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

import javax.inject.Inject;
import javax.sql.DataSource;

import org.edu.dao.IF_MemberDAO;
import org.edu.vo.MemberVO;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

/**
 * JUnit 자바단위테스트이고, DataSource 지정 후 DB(Hsql, Mysql, Oracle) 접속,
 * 데이터베이스 테이블에 Create, Read, Update, Delete 테스트용 클래스
 * @author sieunlee
 *
 */
@RunWith (SpringJUnit4ClassRunner.class)
@ContextConfiguration (locations= {"file:src/main/webapp/WEB-INF/spring/**/*.xml"})
@WebAppConfiguration
public class DataSourceTest {

	@Inject 
	IF_MemberDAO memberDAO;

	@Test
	public void selectMember() throws Exception {
		List<MemberVO> memberList = memberDAO.selectMember();
		System.out.println("회원리스트 테스트입니다.");
		System.out.println(memberList.toString());
	}
}

- MemberDAO 인터페이스객체를 주입한다.

- 리스트형의 memberList 변수에 selectMember라는 id를 가진 쿼리(MemberMapper에 저장)로 호출한 데이터 값(MemberVO 클래스의 데이터)을 저장한다. 

- toString() 호출 -> 출력

정상 실행 된다면, toString이 두번 출력된다.


<다음 날 정리해 본 내용>

우리가 DB에서 어떻게 데이터를 가져오는지 JUnit test case를 통해 알아본다.

root-context.xml에 여러 설정을 추가, bean으로 등록 (의존성추가)

 

< 쿼리 실행 테스트 >

쿼리생성(mapper.xml) -> 쿼리호출메소드생성 DAO(IF_MemberDAO, MemberDAOImpl) -> 테스트(DataSourceTest.java)