이 글은 Java Spring Framework의 JUnit 환경에서 작성되었지만, 다른 프레임워크나 언어에서도 비슷한 상황이 발생할 수 있는 내용을 다루고 있습니다.
결론부터 말하면,
auto increment 되돌리는 방법
ALTER TABLE table_name AUTO_INCREMENT = 10;
@Transactional에 어떤 옵션을 줘도 자동으로 편하게 되돌릴 수 있는 방법은 없는 듯하다.
때문에 테스트 코드 실행 전 미리 현재의 AUTO_INCREMENT 값을 기록해 두었다가 위의 쿼리문을 통해 되돌려야 한다.
하지만,
진짜 결론은 이런 테스트 코드를 작성하지 말자.
Robert C. Martin의 『 클린 코드』에서 테스트 코드에 대한 몇 가지 FIRST 원칙이라는 개념을 제시한다.
F: Fast (빠르게) - 테스트는 빠르게 실행되어야 합니다. 느린 테스트는 개발자가 자주 실행하지 않게 만들고, 효과적인 피드백 메커니즘을 방해합니다. I: Isolated (독립적으로) - 테스트는 서로 독립적으로 실행되어야 합니다. 테스트 간에 의존성이 있으면 한 테스트가 실패할 때 다른 테스트도 실패할 가능성이 있습니다. R: Repeatable (반복 가능하게) - 테스트는 언제나 반복 가능해야 합니다. 테스트가 동일한 결과를 보장해야 하며, 외부 환경에 의존하지 않아야 합니다. S: Self-validating (자체 검증 가능하게) - 테스트는 자체적으로 검증 가능해야 합니다. 테스트 결과는 성공 또는 실패로 나와야 하며, 사람이 수동으로 판단해야 할 결과가 아니어야 합니다. T: Timely (적시에) - 테스트는 적시에 작성되어야 합니다. 단위 테스트를 작성하는 것이 복잡하고 시간이 많이 소요될수록, 코드에 문제가 발생할 가능성이 높아집니다. 따라서, 개발자는 코드를 작성하면서 즉시 테스트 코드도 작성해야 합니다.
이 원칙에 따르면 auto increment를 돌린다는 것은 테스트가 서로 독립적이지 않은 상태이거나 (I 위반) , 반복 가능하지 않은 (R 위반) 테스트일 가능성이 높아 보인다. auto increment에 의존적인 상황이라는 것은 자체 검증하지 않은(S 위반) 테스트 일 가능성 또한 높다고 판단된다.
이 글 작성의 원인이 되었던 나의 테스트 코드는 위의 3가지를 정확하게 위반하고 있었다.
고로. 테스트 코드에서 단순히 @Transactional을 통해 rollback 시키는 상황에서 auto increment 값이 rollback 되어 있지 않아서 문제가 생기는 부분이 있다면, 테스트 설계, 혹은 테스트 환경이 잘못되어 있는 것은 아닌지 다시 한번 고민해 보자.
잘못된 내용이나 다른 의견을 리플로 달아주시면 언제든지 감사한 마음으로 피드백 하겠습니다.
마찬가지로 하나의 lecture에도 여러 student가 포함될 수 있는 N:N관계의 DB다.
위와 같이 N : N 관계의 테이블 설정에서는 @ManyToMany 를 아래와 같이 설정할 수 있다.
@Entity
@Getter @Setter
public class Student {
@Id
@Column(name = "student_id")
private Long id;
private String name;
@ManyToMany
@JoinTable(name = "student_lecture"
,joinColumns = @JoinColumn(name = "student_id")
,inverseJoinColumns = @JoinColumn(name = "lecture_id"))
private List<Lecture> lectures = new ArrayList<>();
}
@Entity
@Getter @Setter
public class Lecture {
@Id
@Column(name = "lecture_id")
private Long id;
@ManyToMany(mappedBy = "lectures")
private List<Student> students = new ArrayList<>();
}
하지만 문제는 실제 테이블을 작성하다보면
student_lecture 테이블에 create_time, update_time 등의 다른 칼럼들이 추가될 일은 많은데
@ManyToMany로 Entity의 변수를 매핑하다 보면 student_lecture 테이블에 다른 column을 추가할 방법이 없다는 것이다.
그러한 이유로 아래와 같이 별도의 StudentLecture 클래스를 두고 @OneToMany , @ManyToOne을 사용하여 매핑하는 것을 추천한다.
@Entity
@Getter @Setter
public class Student {
@Id
@Column(name = "student_id")
private Long id;
private String name;
@OneToMany(mappedBy = "student")
private List<StudentLecture> studentLectures = new ArrayList<>();
}
@Entity
@Getter @Setter
public class Lecture {
@Id
@Column(name = "lecture_id")
private Long id;
@OneToMany(mappedBy = "lecture")
private List<StudentLecture> studentLectures = new ArrayList<>();
}