Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

Slick 유닛테스트에서 Session관련 중복코드 제거하기

이전 포스팅에서 Play 2.1Slick을 연동하는 방법을 설명했는데 이때 작성한 테스트 코드를 다시 보자.

package models

import org.scalatest.FunSpec
import org.scalatest.matchers.ShouldMatchers
import scala.slick.driver.H2Driver.simple._
import Database.threadLocalSession

class UserSpec extends FunSpec with ShouldMatchers {

  describe("example") {
    it("사용자를 추가하고 조회한다") {
      Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver") withSession {
        // given
        Users.ddl.create
        Users.add(new User("outsider", "Outsider", "example@gamil.com"))
        // when
        val results = Users.findAll
        // then
        results.size should equal(1)
      }
    }
    it("사용자를 추가하고 조회한다 2") {
      Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver") withSession {
        // given
        Users.ddl.create
        Users.add(new User("outsider", "Outsider", "example@gamil.com"))
        // when
        val results = Users.findAll
        // then
        results.size should equal(1)
      }
    }
  }
}

테스트를 하나 더 추가했는데 여기서 보듯이 Slick을 돌리기 위해서 Session이 필요하기 때문에 디비 설정을 위한 세션을 유닛테스트마다 추가해 주어야 한다. 즉, 다음과 같은 코드를 모든 유닛테스트마다 추가해 주어야 한다.

Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver") withSession {
  Users.ddl.create
}

보통 하나의 스펙에서는 같은 디비설정을 사용할 것이고 DDL 정의도 동일할 것이므로 이는 상당한 중복을 발생시키고 불필요한 중복코드로 테스트코드를 읽는데도 방해가 된다. 이 문제를 어떻게 해결해야 할지 알 수 없어서 스택오버플로우에 질문 올렸더니 Slick의 메인개발자인 Stefan Zeiger가 직접 대답을 해주었다. 덕분에 유닛테스트를 다음과 같이 수정할 수 있다.

package models

import org.scalatest.{BeforeAndAfter, FunSpec}
import org.scalatest.matchers.ShouldMatchers
import scala.slick.driver.H2Driver.simple._

class UserSpec extends FunSpec with BeforeAndAfter with ShouldMatchers {

  implicit var session: Session = _

  before {
    session = Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver").createSession()
    Users.ddl.create
  }

  after {
    session.close()
  }

  describe("example") {
    it("사용자를 추가하고 조회한다") {
      // given
      Users.add(new User("outsider", "Outsider", "example@gamil.com"))
      // when
      val results = Users.findAll
      // then
      results.size should equal(1)
    }
    it("사용자를 추가하고 조회한다 2") {
      // given
      Users.add(new User("outsider", "Outsider", "example@gamil.com"))
      // when
      val results = Users.findAll
      // then
      results.size should equal(1)
    }
  }
}

일단 임포트문에서 threadLocalSession을 제거해주고 유닛테스트 앞뒤로 실행할 beforeafter를 사용하기 위해서 ScalaTest의 BeforeAndAfter 트레이트를 믹스인한다. 테스트에서 사용할 Session 변수를 선언하고 before에서 세션을 생성하고 DDL 문을 생성하고 after에서 세션을 닫아준다. 이렇게 작성하면 각 유닛테스트에는 테스트에 필요한 코드만 넣을 수 있고 마찬가지로 각 테스트는 독립적인 세션하에서 실행할 수 있다.

2013/06/07 02:12 2013/06/07 02:12