H2 DB와 JUnit을 사용하여 테스트
JUnit Test를 진행하는데 실제 DB에 있는 데이터를 건들지 않고 테스트를 하고 싶은 마음에 시작한 프로젝트이다. 연습하는 김에 Java로 설정해 보았다.
먼저 Gradle로 라이브러리를 빌드하자
build.gradle
compile group: 'org.springframework', name: 'spring-context', version: '4.3.7.RELEASE'
compile group: 'commons-dbcp', name: 'commons-dbcp', version: '1.2.2'
compile group: 'org.springframework', name: 'spring-jdbc', version: '4.3.7.RELEASE'
compile group: 'org.mybatis', name: 'mybatis-spring', version: '1.2.1'
compile group: 'org.mybatis', name: 'mybatis', version: '3.1.1'
compile group: 'com.h2database', name: 'h2', version: '1.4.192'
testCompile group: 'org.springframework', name: 'spring-test', version: '4.3.7.RELEASE'
testCompile group: 'junit', name: 'junit', version: '4.+'
그다음에는 Java Code로 설정해보자
AppConfig.java
@Configuration
public class AppConfig {
@Autowired
private ApplicationContext applicationContext;
@Bean
public UserDao userDao(SqlSession session) {
return new UserDao(session);
}
@Bean
public DataSource dataSource(){
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:testdb;INIT=RUNSCRIPT FROM 'classpath:init.sql'");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
sessionFactory.setMapperLocations(applicationContext.getResources("classpath:sql/*.xml"));
return (SqlSessionFactory)sessionFactory.getObject();
}
@Bean
public SqlSession session(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
설정중 H2 DB를 사용하기 위해서 dataSource는 BasicDataSource 클래스로 만들어야 한다. (이것 때문에 1시간을 넘게 소비해서 작성해놓는다)
transactionManager 메소드는 Test Code에서 Transaction 어노테이션을 사용하기 위해 작성한다.
그리고 위 코드는 각 메소드에 파라미터를 넣어 줬는데 넣지 않고 아래 코드와 같이 그냥 메소드를 사용해도 된다. 단 throws 되는 Exception 들을 계속 throws 해줘야 한다.
AppConfig.session()
@Bean
public SqlSession session() throws Exception {
return new SqlSessionTemplate(sqlSessionFactory());
}
테스트를 위한 설정은 모두 끝났다. 이제 Dao를 만들어 보자.
UserDao.java
@Repository
public class UserDao {
@Autowired
private SqlSession session;
public UserDao(SqlSession session){
this.session = session;
}
public UserVo findUserById(long id){
return session.selectOne("findUserById", id);
}
public List<UserVo> findAllUsers(){
return session.selectList("findAllUsers");
}
public void insertUser(UserVo user){
session.insert("insertUser", user);
}
public void updateUser(UserVo user){
session.update("updateUser", user);
}
}
Dao에는 두 가지 Select 메소드와 Insert, Update 메소드가 하나씩 있다.
그다음 UserVo이다.
UserVo.java
public class UserVo {
private long id;
private String name;
private String email;
private String password;
public UserVo(){}
public UserVo(long id, String name, String email, String password){
this.id = id;
this.name = name;
this.email = email;
this.password = password;
}
public UserVo(String name, String email, String password){
this.name = name;
this.email = email;
this.password = password;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public UserVo(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void setName(String name) {
this.name = name;
}
public String toString(){
return "id : " + id + ", name : " + name + ", email : " + email + ", password : " + password;
}
}
테스트를 진행하기에 앞서 query문을 작성하자
첫번째는 테스트를 진행하기 전에 만들어질 테이블과 데이터를 입력한 query문이다.
init.sql
DROP TABLE IF EXISTS users;
CREATE TABLE users (
id INT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(10) NOT NULL,
email VARCHAR(20),
password VARCHAR(20)
);
INSERT INTO users(name, email, password) VALUES('testName', 'testEmail@test.com', 'testPassword');
두번째는 CRUD를 진행할 query문이다.
sql/userSql.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">
<mapper namespace="userVo">
<select id="findUserById" resultType="org.gradle.vo.UserVo" parameterType="java.lang.Long">
SELECT id, name, email, password FROM users WHERE id = #{id}
</select>
<select id="findAllUsers" resultType="org.gradle.vo.UserVo">
SELECT id, name, email, password FROM users
</select>
<insert id="insertUser" parameterType="org.gradle.vo.UserVo">
INSERT INTO users (name, email, password)
VALUES (#{name}, #{email}, #{password})
</insert>
<update id="updateUser" parameterType="org.gradle.vo.UserVo">
UPDATE users SET
name = #{name},
email = #{email},
password = #{password}
WHERE ID = #{id}
</update>
</mapper>
이제 테스트를 진행해보자
UserDaoTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class,classes={AppConfig.class})
public class UserDaoTest {
@Autowired
private UserDao userDao;
@Test
@Transactional
public void findUserByIdTest(){
UserVo user = userDao.findUserById(1L);
assertEquals("testName", user.getName());
assertEquals("testEmail@test.com", user.getEmail());
assertEquals("testPassword", user.getPassword());
}
@Test
@Transactional
public void findAllUsersest(){
List<UserVo> users = userDao.findAllUsers();
assertEquals(1, users.size());
UserVo user = users.get(0);
assertEquals("testName", user.getName());
assertEquals("testEmail@test.com", user.getEmail());
assertEquals("testPassword", user.getPassword());
}
@Test
@Transactional
public void insertUserTest(){
List<UserVo> users = userDao.findAllUsers();
assertEquals(1, users.size());
UserVo inser = new UserVo("name", "email", "password");
userDao.insertUser(inser);
users = userDao.findAllUsers();
assertEquals(2, users.size());
UserVo user = users.get(1);
assertEquals("name", user.getName());
assertEquals("email", user.getEmail());
assertEquals("password", user.getPassword());
}
@Test
@Transactional
public void updateUserTest(){
UserVo user = userDao.findUserById(1L);
assertEquals("testName", user.getName());
assertEquals("testEmail@test.com", user.getEmail());
assertEquals("testPassword", user.getPassword());
userDao.updateUser(new UserVo(1L, "name", "email", "password"));
user = userDao.findUserById(1L);
assertEquals("name", user.getName());
assertEquals("email", user.getEmail());
assertEquals("password", user.getPassword());
}
}
모든 코드를 작성했다. 이제 테스트를 해보는 것만 남았다.
typeAlias를 사용 하기위한 코드를 추가해보자
먼저 AppConfig 클래스에 있는 sqlSessionFactory() 메소드에 sessionFactory.setTypeAliasesPackage("org.gradle.vo");를 추가하자 그다음 UserVo 클래스 상단에 @Alias("userVo")을 붙여주고 userSql.xml 파일에서 org.gradle.vo.UserVo로 작성한 것들을 userVo로 수정해주면 된다.