오늘 포스팅은 자랑글 좀 하려고한다. 이번주에 좋은 일이 두가지가 있었다.

첫 번째로 제일 기분이 좋았던 일은 스프링캠프와 관련있는 일이다. 스프링캠프에서 연사를 부탁한다는 메일을 받았다. 메일을 읽자마자 솔직히 조금 설레고 떨렸다.. 그리고 이틀동안 아주 많은 고민, 생각을 했다. 솔직히 너무너무 해보고 싶은데 아직은.. 내가 다른 개발자앞에서 자신있게 발표할 자신이 없었다. 그래서 너무너무 죄송한 일이지만 다음에 기약하기로 하였다. 하지만 난 블라인드 티켓 구매자니 좋은 강의를 듣고 와야 겠다. 좀 더 많은 공부를 한 후.. 좀 더 나은 개발자가 된 후 내년에는 꼭 도전해보려 한다. 다시 공부를 열심히 할 계기가 생긴 거 같아서 좋다. 아무튼 이런 기분 좋은 일이 있었다
그리고 스프링캠프 스태프분들 감사해요!!

첫 번째 기분 좋은 일이 스프링과 관련있었다면.. 두 번째도 마찬가지로 스프링과 관련있는 일이다.(반전은 없다) 더 정확히는 스프링 부트와 Mybatis? 아무튼.. 현재 회사에서 데이터를 다룰때 JPA를 주로 사용한다. 대부분의 개발이 JPA로 충분히 개발이 가능하다. 복잡한 쿼리는 Querydsl이나 JdbcTemplate를 사용하곤 했다. 뭐 저정도만 해도 웬만한 개발을 할 수 있다고 생각한다. 그래서 Mybatis는 거의 신경쓰지 않았다. 근데 스케쥴러를 개발하다보니까 복잡한 쿼리들이 난무 할 거 같았다. 그래서 JPQL로 해결할 수 없는 쿼리가 나올 수도 있을 거 같아서 Querydsl은 후보에서 뺏다..(하지만 결론은 Querydsl 만으로도 충분 했다.) 그래서 다음 후보는 JdbcTemplate을 사용했다. 다 좋긴 한데 쿼리가 보기가 조금 힘들었다. java는 String Literals을 지원 하지 않아서 보기가 더 힘들다. 그래서 kotlin을 사용해서 String Literals 만 만드는 코드를 넣을까도 생각했다. 그러면 보기에는 좀 더 쉬우니까.. 근데 그것도 그냥 생각만 하고 Mybatis 를 보기 시작했다. 예전에 Spring boot Mybatis 포스팅을 한게 있어서 한번 다시 살펴봤다. 자동 설정도 지원하니 딱히 어려운 부분도 없어서 금방 코드를 교체했다. 그러고 나서 테스트코트를 짠 후에 잘 돌아 갔는데 문득 생각난게 있었다. Spring boot 1.4부터 추가되었던 Test 어노테이션들이 생각났다. 그래서 Mybatis에도 비슷한 어노테이션이 있나 싶어서 찾아봤는데 어라? 없네.. 흠 그럼 한번 만들어볼까? 해서 모듈 2개를 추가 하고 Mybatis github 에 풀리퀘를 날렸다. 처음이다 풀리퀘를 날린게.. 오오!! 근데 수정사항들은 몇가지 요청했다. 그리고 나서 요청한 코드들을 수정한 후 다시 푸시를 했더니 엊그제 머지가 되었다. 하하하 처음으로 open source에 커밋을 했다! 안그래도 스프링캠프 때문에 기분이 좋았는데 완전 더 기분이 좋았다. 실제 만든 모듈은 mybatis-spring-boot-starter-testmybatis-spring-boot-test-autoconfigure 모듈 두개다. 뭐 솔직히 코드는 얼마 없다. 그리고 그렇게 대단한 코드를 작성한건 아니지만 처음으로 풀리퀘를 날린거니까 그래도 나름 자부심을 느낀다.
언젠간 Spring 프로젝트 에도 풀리퀘를 날린 날을 기대하며..

@MybatisTest 여기에 가보면 @author에 wonwoo가 똬악! 현재는 스냅샷인데 이번주 혹은 다음주에 릴리즈 될 예정이라고 한다.

일단 영어를 못하니 문서는 안쓰는걸로.. 뭐 자기들이 이슈에는 문서업데이트 해야 된다고 하니.. 알아서 잘 써주겠지.. 나는 한글문서만 여기에 쓰는 걸로.. 물론 샘플 테스트 코드도 올려놨다.

SampleSqlSessionTest는 여기 SampleMapperTest는 여기에서 샘플 코드를 확인할 수 있다. 하지만 현재는 Spring boot 1.4.x만 지원된다. 1.5에서는 추가된 API가 있어 수정 또한 해야 된다. 물론 Mybatis starter 도 현재는 1.4.x만 지원하니 참고하면 되겠다. 조만간 1.5로 업그레이드 할 듯 하다.

그럼 간단하게 한번 사용해보도록 하자!

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter-test</artifactId>
        <version>1.2.1-SNAPSHOT</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.2.1-SNAPSHOT</version>
    </dependency>

    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>
</dependencies>

<repositories>
    <repository>
        <id>sonatype-oss-snapshots</id>
        <name>Sonatype OSS Snapshots Repository</name>
        <url>https://oss.sonatype.org/content/repositories/snapshots</url>
    </repository>
</repositories>

메이븐에는 위와 같이 넣자. 현재 스냅샷이라 repository를 설정해야 한다. 릴리즈가 되면 제거해도 된다. 여기서 중요한게 필자가 만든 mybatis-spring-boot-starter-test 이다. 하하
근데 spring-boot-starter-test를 포함시킬껄 그랬나? 해당 디펜더시를 optional을 true로 줘서.. spring-boot-starter-test도 디펜더시 받아야 된다

@Mapper
public interface SampleMapper {
  Sample findByname(String name);
}

Mapper 테스트 위해 간단하게 샘플 인터페이스를 작성하자. 그리고 해당 샘플 도메인도 작성하자.


public class Sample { private Long id; private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }

그리고 application.properties에 다음과 같이 작성하자.

mybatis.type-aliases-package=com.example.test
mybatis.mapper-locations=sample.xml
spring.datasource.schema=schema.sql

위의 설정은 필자가 예전에 포스팅한게 있으니 참고하면 되겠다.
그러면 스키마도 작성하고..

create table sample (id int, name varchar);

샘플 mapper.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="com.example.test.SampleMapper">
  <select id="findSample" resultType="Sample">
        select * from sample
    </select>

  <select id="findByname" resultType="Sample">
        select * from sample where name = #{name}
    </select>

  <insert id="saveSample">
        insert into sample values(#{id}, #{name})
    </insert>
</mapper>

일단 위와 같이 하면 셋팅은 끝이다. 간단하다. 테스트를 작성해보자!

@RunWith(SpringRunner.class)
@MybatisTest
public class MybatisTestApplicationTests {

  @Autowired
  private SampleMapper sampleMapper;

  @Autowired
  private SqlSession sqlSession;

  @Before
  public void setup() {
    Map<String, Object> parameters = new HashMap<String, Object>();
    parameters.put("id", 1);
    parameters.put("name", "wonwoo");
    sqlSession.insert("saveSample", parameters);
  }

  @Test
  public void sqlSessionTest() {
    Sample findSample = sqlSession.selectOne("findSample", 1L);
    assertThat(findSample.getId()).isNotNull().isEqualTo(1L);
    assertThat(findSample.getName()).isNotNull().isEqualTo("wonwoo");
  }

  @Test
  public void sampleMapperTest() {
    Sample findSample = sampleMapper.findByname("wonwoo");
    assertThat(findSample.getId()).isNotNull().isEqualTo(1L);
    assertThat(findSample.getName()).isNotNull().isEqualTo("wonwoo");
  }
}

아주 심플하게 @MybatisTest 어노테이션만 사용하면 된다. 그럼 @MybatisTest 어노테이션이 Mybatis의 SqlSession과 @Mapper 어노테이션들도 빈으로 등록한다. 물론 테스트이므로 데이터들은 롤백된다. 이렇게 스프링 컨테이너를 다 올릴필요 없이 Mybatis와 연관된 것들만 올리니 테스트가 좀 더 빠르게 진행 된다. 테스트 해본 결과 대략 1초에서 1.2초 정도 차이가 난다. 많은 체감은 느낄수 없겠군… 흠 테스트 코드가 많으면 조금 체감을 할 수 있지 않을까?

아무튼 오늘은 필자가 만든 Spring Mybatis test에 대해서도 알아봤다!
Spring boot에 Mybatis 사용하시는 개발자분들은 아주 많이 많이 사용해주세요!!