유닛테스트시, mock 객체 활용의 어려움.

2014-01-06 01:44

루비 Rspec을 이용한 테스트를 작성중이다. 이번에는 객체별 완전 독립 테스트를 하려고 노력했다. 그런데 mock 객체에 아직 익숙하지 않아 굉장히 어렵다.

아직 훈련이 덜 된 탓일 수 있지만 mock을 사용하여 완전 독립적인 테스트를 만들다 보니, 실제구현보다 테스트에 더 많은 시간이 할애된다. 또, 객체간의 인터페이스 구성이 훨씬 복잡하게 느껴진다.

밑의 예제는 지뢰찾기에서 '1x1 그리드에서 셀이 마인인 경우, 그냥 이긴다'에 대한 테스트코드이다.

describe Grid do
  before :each do 
    @grid = Grid.new
  end


  context '1x1 그리드에서 셀이 마인인 경우,' do
    it '그냥 이긴다.' do
      cell = double('Cell')
      cell.stub(:mine?) { true }
      @grid.should_receive(:cells) { [cell] }
      @grid.win?.should be_true
    end
  end
end

위 예에서 볼 수 있듯이 Grid는 Cell이라는 객체와 의존관계에 있다. 하지만 Cell을 Mock 객체화 하여 테스트함으로써, 실제 코드에는 Cell 클래스 자체가 없다.

바로 여기에서 의문점이 있다. 예전에는 Grid를 만들면서 Cell이 필요한 부분은 바로 Cell 클래스를 만들었다. 그래서 Grid를 만들때 정한 Cell과의 인터페이스는 바로바로 Cell에 적용되었다.

하지만 지금은 마치 Grid를 완벽하게 다 개발해 놓고, 나중에 Cell를 따로 개발할 수 있는 기분이다. 그래서 Grid를 만들때 정한 Cell과의 인터페이스를 당장 Cell에 적용할 필요가 없다. 그럼 지금 Grid에서 Cell에 대한 인터페이스를 정해놓으면, 나중에 Cell을 만들때 다시 Grid 테스트를 들여다 봐야하는건가?

마치 모듈 하나하나 만들듯이 Grid, Cell 각각 따로따로 만들고 있는 기분이다. 이런 Isolation 테스트는 시간도 많이 소모되어 과도한 거 같다는 생각도 하고 있다. 하지만 이번 스터디에는 객체마다 완전 독립적인 테스트를 구현해볼것이다.

2개의 의견 from SLiPP

2014-01-07 02:48

Cell 테스트를 만들다 보니, 내가 왜 Grid 테스트를 만들때 힘이 들었는지 알겠다. Cell 같은 경우는 다른 객체에 대한 Dependency가 없다. 그리고 지뢰찾기에서 가장 근원적인 객체에 해당한다. 나는 여태껏 근본적인 객체를 먼저 만들지 않고 Grid라는 큰 틀을 먼저 만들고 있었다.(비록 1x1 이라도) 그래서 Grid 테스트를 만들때 어려웠던 것으로 추측한다.

Cell 테스트는 Mock 객체 자체가 필요없다. 혼자만으로도 잘 살아가는 객체다. Cell을 만들고 나니 Row 테스트도 쉽게 만들 수 있었고, Grid 테스트도 쉽게 만들수 있었다.

Row 테스트에서는 Cell을 Mock으로 만들고, Grid 테스트에서는 Row를 Mock으로 만들었다. 좀더 근원적인 객체에서부터 시작하니 따로따로 만들고 있다는 기분도 없어지고, 인터페이스도 쉽게 짤 수 있었다. 정말 기본적인걸 놓치고 있었구나.

2014-01-07 09:46

좋은 시도를 하고 있네. 애플리케이션을 개발하는 관점에 두 가지 접근 방식이 있다. Top Down 접근 방식과 Bottom Up 접근 방식이다. 이 두 가지 중 어떤 접근 방식이 맞다는 것은 없고, 그때 그때의 상황에 따라 적합한 방법을 선택할 필요가 있다고 본다. 이와 관련해서는 http://www.andreas-kraus.net/blog/development-methods-top-down-and-bottom-up-method/ 문서 보면 도움이 될 듯 하다. 아님 온라인 상에서 top down vs bottom up development로 검색해봐도 좋은 문서들 많다.

원 글의 첫 번째 접근 방식은 Top Down 방식의 접근 방식이고, 댓글의 접근 방식은 Bottom Up의 접근 방식이라고 봐도 될 듯하다. 즉, Grid의 요구사항을 만족하기 위해 세부 구현은 뒤로 미루는 접근 방식을 취했다. 댓글의 경우에는 가장 기본이 되는 기능을 구현한 후 여기서부터 단계적으로 확장해가는 방식을 취했다. 한 프로젝트 내에서도 경우에 따라 두 가지 접근 방식을 혼용하는 경우도 있다. 두 가지를 모두 경험해보고 자신에게 맞는 개발 방식을 찾아보는 것도 좋은 연습이 된다. 최근에는 사용자의 요구사항에 초점을 맞추면서 Top Down 접근 방식이 좀 더 우세하다는 느낌이다. 아무래도 도메인 지식이 명확하지 않은 경우에는 Top Down 접근 방식이 더 유리할 수도 있다는 생각이 든다.

다시 원래 글로 돌아가서 이야기해보자. 네가 1 by 1까지 구체화해서 개발을 시작했다면 이 단계에서 벌써 Grid를 생각한 것은 약간 과도한 설계를 한 것은 아닐까라는 생각을 한다. 1 by 1이기 때문에 이 자체를 하나의 Cell로 보고 개발을 시작할 수 있다고 본다. 그럼 자연스럽게 Bottom Up 개발 방식으로 접근할 수 있을거야. 만약 Top Down 접근 방식으로 개발을 시작하려 한다면 3 by 3 정도로 지뢰찾기의 기본적인 요구사항을 대부분 포함하고 있는 규모에서 시작하는 것이 좋을 것이라 생각한다. 즉, 최초 시작할 때의 요구사항을 어느 수준에서 시작하느냐도 Top Down 접근 방식과 Bottom Up 접근 방식으로 개발할 것인가에도 영향을 미칠 수 있다고 본다.

Top Down 접근 방식으로 개발하는 과정을 보고 싶다면 "테스트 주도 개발로 배우는 객체 지향 설계와 실천"(스티브 프리먼, 냇 프라이스 지음/이대엽 옮김, 인사이트) 책을 보면 도움이 될 거다. 네가 시도한 첫 번째 접근 방식도 틀린 것이 아니니 이 방식으로도 연습해 보면 좋겠다. 각각의 경험을 비교해 가면서 그 차이점을 느껴봤으면 좋겠다.

의견 추가하기

연관태그

← 목록으로