Slick 유닛테스트에서 Session관련 중복코드 제거하기
이전 포스팅에서 Play 2.1에 Slick을 연동하는 방법을 설명했는데 이때 작성한 테스트 코드를 다시 보자.
1package models
2
3import org.scalatest.FunSpec
4import org.scalatest.matchers.ShouldMatchers
5import scala.slick.driver.H2Driver.simple._
6import Database.threadLocalSession
7
8class UserSpec extends FunSpec with ShouldMatchers {
9
10 describe("example") {
11 it("사용자를 추가하고 조회한다") {
12 Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver") withSession {
13 // given
14 Users.ddl.create
15 Users.add(new User("outsider", "Outsider", "example@gamil.com"))
16 // when
17 val results = Users.findAll
18 // then
19 results.size should equal(1)
20 }
21 }
22 it("사용자를 추가하고 조회한다 2") {
23 Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver") withSession {
24 // given
25 Users.ddl.create
26 Users.add(new User("outsider", "Outsider", "example@gamil.com"))
27 // when
28 val results = Users.findAll
29 // then
30 results.size should equal(1)
31 }
32 }
33 }
34}
테스트를 하나 더 추가했는데 여기서 보듯이 Slick을 돌리기 위해서 Session이 필요하기 때문에 디비 설정을 위한 세션을 유닛테스트마다 추가해 주어야 한다. 즉, 다음과 같은 코드를 모든 유닛테스트마다 추가해 주어야 한다.
1Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver") withSession {
2 Users.ddl.create
3}
보통 하나의 스펙에서는 같은 디비설정을 사용할 것이고 DDL 정의도 동일할 것이므로 이는 상당한 중복을 발생시키고 불필요한 중복코드로 테스트코드를 읽는데도 방해가 된다. 이 문제를 어떻게 해결해야 할지 알 수 없어서 스택오버플로우에 질문 올렸더니 Slick의 메인개발자인 Stefan Zeiger가 직접 대답을 해주었다. 덕분에 유닛테스트를 다음과 같이 수정할 수 있다.
1package models
2
3import org.scalatest.{BeforeAndAfter, FunSpec}
4import org.scalatest.matchers.ShouldMatchers
5import scala.slick.driver.H2Driver.simple._
6
7class UserSpec extends FunSpec with BeforeAndAfter with ShouldMatchers {
8
9 implicit var session: Session = _
10
11 before {
12 session = Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver").createSession()
13 Users.ddl.create
14 }
15
16 after {
17 session.close()
18 }
19
20 describe("example") {
21 it("사용자를 추가하고 조회한다") {
22 // given
23 Users.add(new User("outsider", "Outsider", "example@gamil.com"))
24 // when
25 val results = Users.findAll
26 // then
27 results.size should equal(1)
28 }
29 it("사용자를 추가하고 조회한다 2") {
30 // given
31 Users.add(new User("outsider", "Outsider", "example@gamil.com"))
32 // when
33 val results = Users.findAll
34 // then
35 results.size should equal(1)
36 }
37 }
38}
일단 임포트문에서 threadLocalSession을 제거해주고 유닛테스트 앞뒤로 실행할 before와 after를 사용하기 위해서 ScalaTest의 BeforeAndAfter 트레이트를 믹스인한다. 테스트에서 사용할 Session 변수를 선언하고 before에서 세션을 생성하고 DDL 문을 생성하고 after에서 세션을 닫아준다. 이렇게 작성하면 각 유닛테스트에는 테스트에 필요한 코드만 넣을 수 있고 마찬가지로 각 테스트는 독립적인 세션하에서 실행할 수 있다.
Comments