You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
JdbcTemplate을 제거하여 Fixture로 만들고 또한 Fixture를 보완하는 리팩토링을 진행하였다.
(테스트 코드 또한 리팩토링 대상이라는 말을 몸소 느낄 수 있는 경험이었다.)
개선 이유
해당 부분을 개선하게 된 이유는 테스트 준비 작업이 굉장히 비대해졌기 때문이다.
특히나 Study와 관련된 준비가 거의 모든 테스트에서 필요해졌다. 에를 들어 커뮤니티에 대한 테스트를 진행한다고 하자. 하지만 이는 비즈니스적으로는 Study에 종속적이기 때문에 스터디에 대한 생성이 필요한데, 이 때 스터디는 스터디 참여자나 스터디 태그 등 다른 자원들 또한 필요하다. 따라서 테스트 준비 를 위한 작업이 굉장히 비대해졌으며 다른 거의 모든 테스트에서 Study 관련된 테스트가 필요해지자 이를 편리하게 하기 위해 Fixture를 고려하면서 리팩토링을 진행하게 되었다.
그리고 무엇보다 테스트 코드 또한 하나의 문서역할을 할 수 있어야 하는데 jdbcTemplate을 이용한 테스트 준비 과정은 전혀 가독성이 없다.
실제 테스트하려는 것은 내가 참여한 스터디 목록을 조회한다. 와 스터디 ID가 빈 경우 스턴디 방장 빈 맵을 반환한다. 라고 하는 2가지 동작 밖에 없다. 하지만 이를 준비하기 위해서는 굉장히 긴 초기 준비 작업을 필요로 한다.
심지어는 이것이 한 눈에 들어오지도 않으며 무엇을 하려고 하는지도 모르겠다. 그리고 이를 이해하기 위해서 우리의 DB 테이블이 어떻게 구성되어있는지 또한 이해해주어어야 하며 우리의 비즈니스를 완전히 이해하고 있어야한다.
우선 Study를 생성하기 위해서는 스터디에 붙는 태그들 또한 필요하게 되며, 스터디 방장과 스터디의 참여자가 필요하다. 그리고 우리는 이 모든것을 jdbcTemplate의 update() 메소드를 통해서 일일이 다 넣어주고 있었다. 굉장히 별로인 코드다.
짱구, 그린론, 디우, 베루스라는 member들을 저장한다. 그리고 자바 스터디, 리액트 스터디 등등을 생성한다. 이 때 매개변수로 스터디장의 id와 스터디 참여자들의 memberId를 넘겨주고 있다. 아직 자바_스터디 생성시에 넘기는 인자들이 무엇을 의미하는지는 잘 모를 수는 있지만 이전보다 훨씬 가독성이 좋아진 것을 알 수 있다.
여기에 더해서 JPA 의 장점 또한 누릴 수 있는데, 스터디를 저장하면서 동시에 스터디 참여자들(study_member 테이블)을 저장할 수 있는 것이다. 이전에는 각 테이블 별로 insert 문을 작성해 날렸어야하지만, JPA 를 활용하여 테스트 준비 작업을 진행하게 되면서 JPA가 알아서 객체를 저장할 때 연관된 테이블이 있다면 insert 문을 날려주게 되는 것이다. 보다 객체지향적으로 우리는 테스트를 준비할 수 있게 되었다.
merge 와 persist
여기서 member를 static한 하나의 객체를 만들어주지 않고 호출시마다 생성하는 이유가 궁금할 수 있다.
(구체적으로는 id를 가지지 않는다는게 핵심이다. id를 가지지 않는 Member 객체를 매번 생성해서 반환한다.)
그 이유는 JPA를 통해서 저장을 하고 있고, 그러한 객체들이 모두 Auto Increment 값으로 PK(id)를 가지고 있기 때문이다.
그런데 만약 @BeforeEach 가 붙은 메소드, 즉 테스트 준비에 해당하는 부분에서 디우를 Member 들 중 맨 처음으로 저장하면 어떻게 될까? 우선 현재 DB에 3L 이라는 값이 있는지를 확인한다. 즉 우선적으로 select 구문이 나가게 된다. 하지만 현재 DB에 3L 에 해당하는 Member 가 없으므로 merge가 일어나지 않고 persist 가 수행된다.
위의 사진은 이를 테스트하기 위한 간단한 테스트를 작성한 모습이다. 아래 쿼리문이 나간 것과 sout 으로 출력하는 구문을 보자.
가장 먼저 (그림에서 짤리긴 했지만) member 객체가 id값을 가지고 있기 때문에 select문이 날아간다. 하지만 DB에는 없다는 결과가 나오게 되고, 따라서 merge가 아닌 persist 가 일어나게 된다. 그러므로 Auto Increment에 따라서 id에 default(자동 증가) 가 들어간 insert 쿼리가 날아가게 되고 그 결과 id 값이 1인 member 가 저장되게 되는 결과를 우리는 sout 을 통해서 확인할 수 있다.
여기서 문제가 발생한다. 만약 Study에 owner로써 우리는 디우 를 저장했다고 해보자.
그리고 검증문에서 다음과 같은 검증문을 사용한다고 생각해보자.
이 때, 디우.getId() 는 Fixture 로써 우리가 미리 메모리에 만들어 두었으므로 3L 이라는 값으로 고정적이다. 하지만 여기에 우리가 스터디 생성시에 디우 라는 Fixture를 사용했는지와는 무관하게 DB에 저장되는 순간 어떤 id값이 할당되었을지 우리는 알 수 없다.
즉 테스트 픽스쳐의 다음과 같은 정의에서 매번 동일한 결과를 얻을 수 있게.. 라는 말에도 어긋나는 것이다.
(물론 메모리에 저장된 객체 자체는 매번 동일한 결과지만 이를 DB에 저장한 이후에는 매번 동일한 결과를 얻을 수 없다.)
테스트 픽스쳐란 테스트를 반복적으로 수행할 수 있게 도와주고 매번 동일한 결과를 얻을 수 있게 도와주는 기반이 되는 상태나 환경을 의미한다. 여러 테스트에서 공용으로 사용할 수 있는 테스트 픽스쳐는 테스트의 인스턴스 변수 혹은 별도의 클래스로 모아둔다.
따라서 id 값이 없는 객체를 생성하는 메소드를 static final 하게 선언해놓고 필요한 곳에서 해당 메소드를 호출해 사용하도록 하였다. 그리고 해당 메소드에서 반환되는 객체를 저장하여 auto-increment 하는 id 값을 사용할 수 있도록 해주었다.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
디우의 모아모아 4차 데모 후기 - 테스트코드 JdbcTemplate 제거
JdbcTemplate을 제거하여 Fixture로 만들고 또한 Fixture를 보완하는 리팩토링을 진행하였다.
(테스트 코드 또한 리팩토링 대상이라는 말을 몸소 느낄 수 있는 경험이었다.)
개선 이유
해당 부분을 개선하게 된 이유는
테스트 준비
작업이 굉장히 비대해졌기 때문이다.특히나
Study
와 관련된 준비가 거의 모든 테스트에서 필요해졌다. 에를 들어 커뮤니티에 대한 테스트를 진행한다고 하자. 하지만 이는 비즈니스적으로는 Study에 종속적이기 때문에 스터디에 대한 생성이 필요한데, 이 때 스터디는 스터디 참여자나 스터디 태그 등 다른 자원들 또한 필요하다. 따라서테스트 준비
를 위한 작업이 굉장히 비대해졌으며 다른 거의 모든 테스트에서 Study 관련된 테스트가 필요해지자 이를 편리하게 하기 위해 Fixture를 고려하면서 리팩토링을 진행하게 되었다.그리고 무엇보다 테스트 코드 또한 하나의 문서역할을 할 수 있어야 하는데 jdbcTemplate을 이용한 테스트 준비 과정은 전혀 가독성이 없다.
예를 들어 다음 코드를 보자.
실제 테스트하려는 것은 내가 참여한 스터디 목록을 조회한다. 와 스터디 ID가 빈 경우 스턴디 방장 빈 맵을 반환한다. 라고 하는 2가지 동작 밖에 없다. 하지만 이를 준비하기 위해서는 굉장히 긴 초기 준비 작업을 필요로 한다.
심지어는 이것이 한 눈에 들어오지도 않으며 무엇을 하려고 하는지도 모르겠다. 그리고 이를 이해하기 위해서 우리의 DB 테이블이 어떻게 구성되어있는지 또한 이해해주어어야 하며 우리의 비즈니스를 완전히 이해하고 있어야한다.
우선 Study를 생성하기 위해서는 스터디에 붙는 태그들 또한 필요하게 되며, 스터디 방장과 스터디의 참여자가 필요하다. 그리고 우리는 이 모든것을 jdbcTemplate의 update() 메소드를 통해서 일일이 다 넣어주고 있었다. 굉장히 별로인 코드다.
id가 없는 객체를 반환하는 Fixture
위와 같은 Fixture를 만들어두고 사용함으로써, 이전에
@BeforeEach
어노테이션이 붙은 테스트 준비 단계는 다음과 같이 간단하게 수정될 수 있었다.짱구, 그린론, 디우, 베루스라는 member들을 저장한다. 그리고 자바 스터디, 리액트 스터디 등등을 생성한다. 이 때 매개변수로 스터디장의 id와 스터디 참여자들의 memberId를 넘겨주고 있다. 아직 자바_스터디 생성시에 넘기는 인자들이 무엇을 의미하는지는 잘 모를 수는 있지만 이전보다 훨씬 가독성이 좋아진 것을 알 수 있다.
여기에 더해서 JPA 의 장점 또한 누릴 수 있는데, 스터디를 저장하면서 동시에 스터디 참여자들(study_member 테이블)을 저장할 수 있는 것이다. 이전에는 각 테이블 별로 insert 문을 작성해 날렸어야하지만, JPA 를 활용하여 테스트 준비 작업을 진행하게 되면서 JPA가 알아서 객체를 저장할 때 연관된 테이블이 있다면 insert 문을 날려주게 되는 것이다. 보다 객체지향적으로 우리는 테스트를 준비할 수 있게 되었다.
merge 와 persist
여기서 member를 static한 하나의 객체를 만들어주지 않고 호출시마다 생성하는 이유가 궁금할 수 있다.
(구체적으로는 id를 가지지 않는다는게 핵심이다. id를 가지지 않는 Member 객체를 매번 생성해서 반환한다.)
그 이유는 JPA를 통해서 저장을 하고 있고, 그러한 객체들이 모두 Auto Increment 값으로 PK(id)를 가지고 있기 때문이다.
예를 들어 다음과 같은 객체를 생각해보자.
그리고 이 때,
디우_아이디
는 PK이며 3L 이라는 값이라고 하자.그런데 만약
@BeforeEach
가 붙은 메소드, 즉 테스트 준비에 해당하는 부분에서 디우를 Member 들 중 맨 처음으로 저장하면 어떻게 될까? 우선 현재 DB에 3L 이라는 값이 있는지를 확인한다. 즉 우선적으로 select 구문이 나가게 된다. 하지만 현재 DB에 3L 에 해당하는 Member 가 없으므로 merge가 일어나지 않고 persist 가 수행된다.위의 사진은 이를 테스트하기 위한 간단한 테스트를 작성한 모습이다. 아래 쿼리문이 나간 것과 sout 으로 출력하는 구문을 보자.
가장 먼저 (그림에서 짤리긴 했지만) member 객체가 id값을 가지고 있기 때문에 select문이 날아간다. 하지만 DB에는 없다는 결과가 나오게 되고, 따라서 merge가 아닌 persist 가 일어나게 된다. 그러므로 Auto Increment에 따라서 id에 default(자동 증가) 가 들어간 insert 쿼리가 날아가게 되고 그 결과 id 값이 1인 member 가 저장되게 되는 결과를 우리는 sout 을 통해서 확인할 수 있다.
여기서 문제가 발생한다. 만약 Study에 owner로써 우리는
디우
를 저장했다고 해보자.그리고 검증문에서 다음과 같은 검증문을 사용한다고 생각해보자.
이 때,
디우.getId()
는 Fixture 로써 우리가 미리 메모리에 만들어 두었으므로3L
이라는 값으로 고정적이다. 하지만 여기에 우리가 스터디 생성시에디우
라는 Fixture를 사용했는지와는 무관하게 DB에 저장되는 순간 어떤 id값이 할당되었을지 우리는 알 수 없다.즉 테스트 픽스쳐의 다음과 같은 정의에서
매번 동일한 결과를 얻을 수 있게..
라는 말에도 어긋나는 것이다.(물론 메모리에 저장된 객체 자체는 매번 동일한 결과지만 이를 DB에 저장한 이후에는 매번 동일한 결과를 얻을 수 없다.)
테스트 픽스쳐란 테스트를 반복적으로 수행할 수 있게 도와주고 매번 동일한 결과를 얻을 수 있게 도와주는 기반이 되는 상태나 환경을 의미한다. 여러 테스트에서 공용으로 사용할 수 있는 테스트 픽스쳐는 테스트의 인스턴스 변수 혹은 별도의 클래스로 모아둔다.
따라서 id 값이 없는 객체를 생성하는 메소드를 static final 하게 선언해놓고 필요한 곳에서 해당 메소드를 호출해 사용하도록 하였다. 그리고 해당 메소드에서 반환되는 객체를 저장하여 auto-increment 하는 id 값을 사용할 수 있도록 해주었다.
Beta Was this translation helpful? Give feedback.
All reactions