Spring JUnit FK NULL 에러

홍준식·2024년 5월 5일

작가라는 엔티티와 1:N 관계를 갖는 책이라는 엔티티가 있다고 하자.

@Entity
public class Author {  
    @Id  
    private Long authorId;
    
	@OneToMany(mappedBy = "author")  
	private List<Book> books = new ArrayList<>();
}
@Entity
@Builder
@Getter
public class Book {  
    @Id  
    private Long bookId;
    
	@ManyToOne  
	@JoinColumn(name = "author_id")  
	private Author author;

	private String name;
}

책을 추가하는 서비스 로직은 다음과 같다.

@Service
public class BookService {
	private final BookRepository bookRepository;
	private final AuthorRepository authorRepository;
	
	@Transactional
	public Book create(Long authorId, String bookName) {
		Author author = authorRepository.findById(authorId);
		Book book = Book.builder().author(author).name(bookName).build();
		return bookRepository.save(book);
	}
}

작가의 모든 책 정보를 조회하는 서비스 로직은 다음과 같다.

@Service
public class AuthorService {
	private final BookRepository bookRepository;
	private final AuthorRepository authorRepository;

	@Transactional
	public Author create() {
		Author author = Author.builder().build();
		return authorRepository.save(author);
	}

	@Transactional
	public List<Book> listAllBooksByAuthor(Long authorId) {
		return bookRepository.findByAuthor_AuthorId(authorId);
	}
}
@DataJpaTest
public class AuthorServiceTest {
	@Autowired
	BookService bookService;

	@Autowired
	AuthorService authorService;

	@Test
	void listAllBooksByAuthorTest() {
		author = authorService.create();
		bookService.create(author.getAuthorId(), "newBook");

		List<Book> books = authorService.listAllBooksByAuthor(author.getAuthorId());

		assertThat(books.size()).isEqualTo(1);
	}
}

위의 결과 books는 null이 되고 테스트가 틀렸다고 나오게 된다.

원인은 DataJpaTest로 묶인 모든 테스트는 하나의 트랜잭션을 공유하기 때문이다.
DataJpaTest는 테스트를 하나의 트랜잭션으로 묶어 테스트 종료 후 트랜잭션을 반영하지 않고 롤백하여 함수 단위의 데이터베이스 초기화를 제공한다.

하지만 이러한 원인으로 author에서는 OneToMany로 되어있는 books가 조회되지 않는 결과가 발생한다.

해결 방법으로는
entityManager.clear()를 사용하면 된다.
clear 메서드는 컨테스트 내에 캐시된 모든 엔티티를 제거하고 다시 데이터베이스에서 로딩하게 되는데 이를 통해 엔티티의 변경을 반영할 수 있다.

@DataJpaTest
public class AuthorServiceTest {
	@Autowired  
	private TestEntityManager entityManager;

	@Autowired
	BookService bookService;

	@Autowired
	AuthorService authorService;

	@Test
	void listAllBooksByAuthorTest() {
		author = authorService.create();
		bookService.create(author.getAuthorId(), "newBook");
		entityManager.clear();
		
		List<Book> books = authorService.listAllBooksByAuthor(author.getAuthorId());

		assertThat(books.size()).isEqualTo(1);
	}
}

0개의 댓글