포스트

2021-05-23-TIL

2021-05-23-TIL

Q. 테스트 코드로 insert한 결과는 db에 반영이 안되는가?

답은 아래 @Transactional 절에 정리했다. 테스트 클래스에 붙인 @Transactional 때문에 테스트가 끝날 때마다 롤백되고 있었다.


CORS 문제

리액트로 실행되는 프론트 서버는 localhost:3000 주소를 사용하는데, JSON 데이터를 받아오는 서버가 AWS의 주소이므로 서로 오리진이 달라서 발생하는 문제이다. 이는 iOS에서는 발생하지 않으며, 프론트는 자체 서버가 구동되므로 발생하는 문제이다. 이 문제를 해결하기 위해서 임시적으로 @CrossOrigin을 각 컨트롤러에 붙여주면 된다. 나중에 배포할 때는 이것을 제거하고 프론트 서버와 함께 배포하면 된다.

결론: 개발할 때는 @CrossOrigin으로 배포하고, 나중에 프론트 서버랑 합칠 때는 애노테이션 빼고 프론트 서버는 Nginx에, 백엔드 서버는 Tomcat에 올리면 된다.

CORS의 원리는 2021-05-11 TIL에 정리했다. 결론의 배포 구성이 문제를 없애는 이유는 브라우저 입장에서 origin이 하나가 되기 때문이다. nginx가 정적 파일(리액트 빌드 결과)을 직접 내보내고, /api 같은 경로만 proxy_pass로 톰캣에 넘기면 페이지와 API가 같은 스킴, 호스트, 포트를 쓴다(nginx Beginner’s Guide). 교차 출처 요청이 아니므로 CORS 헤더가 필요 없다.

개발 중에 @CrossOrigin을 컨트롤러마다 붙이는 대신 WebMvcConfigurer.addCorsMappings로 허용 origin을 한곳에 두면, 나중에 지울 때도 한 파일만 고치면 된다(Spring 문서).


@Transactional

1
2
3
4
5
@SpringBootTest
@Transactional
class RoomRepositoryTest {
		...
}

테스트 코드의 클래스에 아무 생각없이 붙였던 @Transactional애노테이션은 해당 테스트 코드 전체를 트랜잭션으로 보고, 별도의 커밋을 수행하지 않으면 롤백하도록 해준다. 따라서 해당 애노테이션을 없애고 Insert 쿼리를 수행하면 DB에 해당 데이터가 저장되는 것을 확인할 수 있다.

1
2
3
Executing prepared SQL statement
...
Rolled back transaction for test: [DefaultTestContext@3aaca039 testClass = RoomRepositoryTest, testInstance = ...

@Transactional을 붙이면 해당 로그가 출력되는데, 트랜잭션 커밋이 이루어지지 않아서 다시 롤백하는 로그가 출력된다. 테스트 코드는 테스트일 뿐이므로 롤백하는 것이 타당해보인다.

Spring 테스트 문서도 테스트가 관리하는 트랜잭션은 기본적으로 테스트가 끝나면 롤백된다고 설명한다. 클래스에 붙이면 각 테스트 메서드가 각자 트랜잭션 안에서 돈다. 그래서 테스트끼리 데이터가 섞이지 않고, 매번 같은 상태의 DB에서 시작할 수 있다.

실제로 DB에 남겨서 확인하고 싶을 때는 애너테이션을 지우는 대신 해당 테스트에 @Commit(또는 @Rollback(false))을 붙이는 방법이 있다. 클래스 단위의 롤백 정책은 그대로 두고 필요한 테스트만 커밋하게 할 수 있다.

1
2
3
4
5
@Test
@Commit
void insertAndKeep() {
    roomRepository.save(room);
}

한 가지 주의할 점은 @BeforeEach 같은 생명주기 메서드에는 테스트의 @Transactional이 적용되지 않는다는 것이다. 또 @SpringBootTest에 webEnvironment = RANDOM_PORT를 주고 실제 HTTP 요청을 보내면 클라이언트와 서버가 다른 스레드, 다른 트랜잭션에서 돈다. 이 경우 서버에서 시작한 트랜잭션은 롤백되지 않는다(Spring Boot 테스트 문서).


TODO

  • VPC 설정
  • 배포 자동화
  • OAuth 적용
  • Nginx 설정 및 프론트서버 배포
참고한 자료외부 출처 5

외부 출처

이 글은 저작권자의 CC BY 4.0 라이선스를 따릅니다.

댓글

아직 댓글이 없습니다