인프런 워밍업 클럽 스터디 3기 - 백엔드 클린 코드, 테스트 코드 미션 - Day 16

Layered Architecture는 왜 사용하는 걸까?
핵심 개념: 관심사의 분리 (Separation of Concerns)
Layered Architecture의 핵심 목적은 관심사의 분리입니다.
그렇다면 왜 관심사를 분리해야 할까요?
가장 큰 이유는 유지보수성과 확장성 때문입니다.
사용자의 요청이 들어왔을 때, 각 Layer가 명확한 책임을 갖고 동작한다면 코드 수정이나 기능 추가가 훨씬 쉬워집니다.
Spring Boot에서의 관심사 분리
Spring Boot로 개발할 때 우리는 자연스럽게 관심사를 다음과 같이 나누게 됩니다:
Controller (Presentation Layer): 사용자의 요청을 받고 응답을 반환
Service (Business Layer): 비즈니스 로직 처리
Repository (Persistence Layer): 데이터베이스 접근 및 처리
아래 예시를 보면서 각 Layer의 역할을 살펴보겠습니다.
Presentation Layer
사용자의 요청을 받고 요청값을 검증 후 반환합니다.
@RestController
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@GetMapping("/login")
public LoginResponse login(@RequestBody @Valid LoginRequest loginRequest) {
return service.login(loginRequest);
}
}
@Vali를 통해 LoginRequest을 검증합니다.
Business Layer
비즈니스 로직을 수행하는 핵심 구간입니다.
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRespository userRepository;
public LoginResponse login(LoginRequest loginRequest) {
Users user = userRepository.findByEmail(loginRequest.email())
.orElseThrow(
LoginErrorCode.EMAIL_NOT_FOUND::exception
);
if(user.matchPassword(bCryptPasswordEncoder, loginRequest.password())) {
throw LoginErrorCode.PASSWORD_NOT_FOUND.exception();
}
return LoginResponse.builder()
.username(user.getUsername)
.build();
}Persistence Layer
데이터베이스 접근을 담당합니다.
public interface UserRepository extends JpaRepository<Users,Long> {
}이렇게 각 레이어가 자신의 역할에 집중하면:
- 수정과 확장이 쉬워지고
- 테스트 코드 작성도 쉬워지며
- 유지보수성이 높아집니다.
테스트 코드 작성
저는 주로 서비스단을 테스트 코드로 작성해서 검증합니다.
서비스쪽이 비즈니스 로직을 담당하고 있는 부분이라 생각하여 제일 중요하다 생각합니다. 그래서 이번에 채팅방 생성하는 테스트 코드를 저의 방식대로 해봤습니다.
@ActiveProfiles("test")
@SpringBootTest
class ChatRoomTest {
@Autowired
private ChatRoomRepository chatRoomRepository;
@Autowired
private UserRepository userRepository;
@Autowired
private BoardRepository boardRepository;
@Autowired
private ChatService chatService;
@DisplayName("방 생성 테스트")
@Test
void createRoom() {
// given
Users user = userRepository.findById(1L).orElseThrow();
Product product = boardRepository.findById(1L).orElseThrow();
Users user2 = userRepository.findById(2L).orElseThrow();
Product product2 = boardRepository.findById(2L).orElseThrow();
ChatRoomRequest request = ChatRoomRequest.builder()
.userId(user)
.productId(product)
.name("테스트 채팅방")
.build();
ChatRoomRequest request2 = ChatRoomRequest.builder()
.userId(user2)
.productId(product2)
.name("테스트 채팅방2")
.build();
List<ChatRoomEntity> chatRoom = ChatRoom.create(List.of(request, request2));
List<ChatRoomEntity> save = chatRoomRepository.saveAll(chatRoom);
// when
var chatRooms = chatRoomRepository.findAll();
// then
assertThat(chatRooms).hasSize(2);
assertThat(chatRooms.get(0).getProductId().getId()).isEqualTo(1L);
assertThat(chatRooms.get(0).getProductId().getId()).isEqualTo(2L);
}
}
application-test.yml을 만들어 테스트 환경을 구성하였으며 그 구성 기반으로 더미 데이터(data.sql)를 만들어서 테스트를 진행했습니다.
댓글을 작성해보세요.