Devon's Tech Blog
close
프로필 사진

Devon's Tech Blog

github: @ImGdevel

  • __ (28)
    • [ 프로젝트 ] (1)
      • MIYOU (0)
      • INSTY (1)
    • [ 기술 스택 ] (12)
      • Webflux (8)
      • ElasticSearch (0)
      • Kafka (0)
      • Security (1)
      • JPA (0)
      • Cache (2)
      • Async & MQ (1)
    • [ 공부 ] (4)
    • [ 트러블슈팅 ] (1)
    • [ 인사이트 ] (3)
  • 홈
  • 태그
  • Github
어느 순간 테스트가 5분 — @MockBean이 컨텍스트 캐시를 깨고 있었다

어느 순간 테스트가 5분 — @MockBean이 컨텍스트 캐시를 깨고 있었다

평소 1분 30초쯤 걸리던 테스트 빌드가 있었다. 슬라이스 테스트가 300개를 넘어가던 어느 시점부터 5분이 됐다. 정확히 언제부터 그랬는지는 기억이 안 나는데, PR 올리고 화장실 다녀와서 커피 받아도 CI가 안 끝나 있는 게 어느 순간 일상이 됐다.처음엔 그냥 "테스트가 많아졌으니까 그렇겠지" 하고 넘겼다. 근데 단순 산수가 안 맞았다. 그 사이 새로 추가된 슬라이스 테스트는 10개 남짓이었는데, 빌드 시간은 5배 가까이 늘어 있었다. 한 테스트당 1초씩 늘었다 해도 10초인데, 6분이 추가된 셈이었다.그래서 들여다봤다.원인Spring의 테스트 컨텍스트 캐시는 ApplicationContext를 한 번 만들어두고 다음 테스트가 같은 설정을 요구하면 재사용한다. 이게 빠른 테스트의 핵심이다. 보통은 @..

  • format_list_bulleted 카테고리 없음
  • · 2026. 2. 13.
픽스처가 두 번째 도메인이 되지 않으려면

픽스처가 두 번째 도메인이 되지 않으려면

테스트가 지옥이 되는 첫 순간은, 의외로 실행이 느려질 때가 아니다. Given을 다섯 번째 쓸 때다.게시글 댓글 테스트 하나를 추가하는데, 댓글을 쓰려면 게시글이 있어야 하고, 게시글이 있으려면 작성자가 있어야 하고, 작성자는 OAuth provider가 있어야 하고… 이 체인이 테스트 본문을 50줄 잠식한다. 그리고 다음 테스트도, 그 다음 테스트도 똑같다.@Testfun `댓글이 정상 추가된다`() { val author = User( email = "test@example.com", nickname = "tester", password = "encoded", role = Role.USER, provider = AuthProvide..

  • format_list_bulleted 카테고리 없음
  • · 2026. 1. 24.
반복되는 테스트 환경에 메타 어노테이션을 만들기

반복되는 테스트 환경에 메타 어노테이션을 만들기

테스트가 30개를 넘어가면, PR 리뷰에서 같은 질문이 계속 반복된다."이거 @SpringBootTest 맞아요? @WebMvcTest 아닌가?" "여기엔 @DataJpaTest가 빠진 것 같은데..." "이 테스트는 unit이에요 integration이에요?"답이 매번 다르고, 같은 사람이 한 달 전과 다르게 답한다. 한 분기쯤 지나면 어노테이션 조합이 팀원 수만큼 늘어나 있다. 새로 합류한 사람의 첫 PR에서는 다섯 가지 다른 어노테이션이 등장하기도 한다.이게 단순한 스타일 문제가 아닌 이유는, "이 테스트가 어떤 종류인가"가 사람마다 다르게 해석되면 빠르게 돌릴 테스트와 느리게 돌릴 테스트의 경계가 무너진다는 데 있다. 그러면 결국 다 같이 느린 모드로 돌리게 되고, 시간이 더 지나면 테스트 자체를..

  • format_list_bulleted 카테고리 없음
  • · 2026. 1. 23.

레이어별 테스트 전략은 어떻게 나누어야 하는가?

"이 테스트가 지금 뭘 검증하는 거였지?"이 글을 쓰게 된 계기제가 작성한 테스트 파일들을 돌아보다 이상한 장면을 발견했습니다.서비스 테스트인데 @DataJpaTest가 붙어 있고, 실제 DB에 insert가 들어가고 있었습니다.컨트롤러 테스트에는 비즈니스 분기 조건이 잔뜩 들어가 있었습니다.통합 테스트를 열어봤더니 verify(repository).save(any()) 같은 Mock 검증이 중간에 섞여 있었습니다.문제는 테스트가 깨졌을 때였습니다.서비스 테스트가 깨졌는데 원인이 JPA 매핑 문제였습니다.컨트롤러 테스트가 깨졌는데 원인이 서비스의 분기 로직이었습니다.어느 레이어의 문제인지 판정이 안 됐습니다.그때 깨달았습니다. 테스트가 뭘 검증하는지 모르면, 실패해도 원인을 찾을 수 없었습니다.처음에는 ..

  • format_list_bulleted 카테고리 없음
  • · 2026. 1. 17.
테스트 더블은 언제 사용하고 언제 남용이 되는가

테스트 더블은 언제 사용하고 언제 남용이 되는가

"이거 Mock으로 감싸면 되지 않나요?"이 글을 쓰게 된 계기이전 글에서 테스트 코드의 필요성과 좋은 테스트의 기준에 대해 정리했습니다. 그 이후로 실제로 테스트를 붙이기 시작했는데, 새로운 종류의 고민이 생겼습니다.서비스 테스트를 하나 작성하려고 클래스를 열었습니다. @Mock을 붙여야 할 필드가 네 개. PostRepository, MemberRepository, PostLikeRepository, 거기에 외부 알림용 클라이언트까지. given().willReturn() 체인을 하나씩 설정하다 보니, 테스트 코드가 프로덕션 코드보다 길어졌습니다.그래도 테스트가 통과하니까 괜찮다고 생각했습니다. 문제는 그 다음이었습니다. 서비스 로직을 리팩터링했는데, 기능은 정상 동작하는데 테스트가 깨졌습니다. 원인..

  • format_list_bulleted [ 인사이트 ]
  • · 2026. 1. 16.
테스트 코드란 왜 필요한가? 좋은 테스트 코드란 무엇인가?

테스트 코드란 왜 필요한가? 좋은 테스트 코드란 무엇인가?

"테스트요? 네, 나중에 붙이려고요." 이 글을 쓰게 된 계기저는 한동안 테스트 코드를 '있으면 좋은 것' 정도로만 생각했습니다.게시글 수정 API 하나를 확인한다고 가정해 보겠습니다. 서버를 띄우고, 로그인해서 토큰을 받고, Postman으로 요청을 보내고, 응답을 확인하고, 혹시 몰라서 DB도 한 번 열어봅니다. 한 번 하는 건 괜찮습니다. 그런데 이걸 예외 처리를 추가할 때도, 리팩터링할 때도, 버그를 고칠 때도 반복하고 있으면 슬슬 회의감이 생깁니다.'이거 매번 내가 손으로 해야 하나?'결정적이었던 건, 한 번은 서비스 로직을 좀 정리했는데 기존에 잘 되던 기능이 깨져 있었던 적이 있었습니다. 제가 수정한 부분은 멀쩡했는데, 그 로직을 쓰고 있던 다른 쪽에서 터진 것이었습니다. 수동으로 확인할 때..

  • format_list_bulleted [ 인사이트 ]
  • · 2026. 1. 15.
Local Cache로 Caffeine 쓰면서 배운 것들

Local Cache로 Caffeine 쓰면서 배운 것들

“Redis 붙이기 전에, 애플리케이션 안에서 할 수 있는 캐싱부터 제대로 써보자.”이 글을 쓰게 된 계기캐시라고 하면 자연스럽게 Redis부터 떠올렸다.나도 처음에는 “캐시 = Redis, 네트워크 뒤에 있는 뭔가 빠른 저장소” 정도로만 생각했다.근데 실제로 API를 최적화해 보니,모든 캐시를 굳이 네트워크 너머에 둘 필요는 없다는 걸 느꼈다.“JVM 안에서만 써도 되는 값”“인스턴스별로 달라도 괜찮은 값”“조금 부정확해도 괜찮은, 읽기 위주의 값”이런 것들은 오히려 로컬 캐시(Local Cache)가 더 잘 맞는 경우가 많았다.그 와중에 Spring에서 가장 손쉽게 쓸 수 있는 라이브러리 중 하나가 바로 Caffeine이다.이 글은,Caffeine이 어떤 특징을 가진 로컬 캐시인지Spring Cach..

  • format_list_bulleted [ 기술 스택 ]/Cache
  • · 2025. 12. 23.
Redis Pub/Sub로 서비스 간 이벤트 다루기

Redis Pub/Sub로 서비스 간 이벤트 다루기

“Kafka를 쓰기엔 무겁고, 그냥 동기 호출만 하기엔 아쉬울 때.”이 글을 쓰게 된 계기마이크로서비스까지는 아니더라도,서비스 레이어가 조금씩 나뉘기 시작하면 자연스럽게 “이벤트” 이야기가 나온다.주문이 생성되면 알림 서비스를 호출해야 하고유저가 가입하면 추천/포인트/메일링 시스템이 반응해야 한다.처음에는 대부분 동기 HTTP 호출로 시작한다.“주문 생성 API 안에서 알림/포인트/메일을 순서대로 호출하면 되지.”근데 서비스가 커질수록,한 서비스의 장애가 다른 서비스까지 전파되고요청 응답 시간이 일관되지 않고“이건 사실 비동기로 처리해도 되는 일인데…”라는 생각이 쌓인다.그 지점에서 가볍게 고려해볼 수 있는 도구 중 하나가 Redis Pub/Sub였다.이 글은,Redis Pub/Sub이 어떤 구조로 동작..

  • format_list_bulleted [ 기술 스택 ]/Async & MQ
  • · 2025. 12. 14.
동기랑 블로킹은 같은 말 아닌가요?

동기랑 블로킹은 같은 말 아닌가요?

과거 면접에서 동기와 비동기, 블로킹과 논블로킹의 차이를 물어봤다. 정확히 어떤 맥락에서 나왔던 질문인지는 기억이 안 나는데, 솔직히 답을 잘 못 했다. 머릿속에서는 "동기는 블로킹, 비동기는 논블로킹" 같은 식으로 굳어 있어서 두 단어를 거의 같은 말처럼 썼고, 면접관이 "둘이 다른 개념입니다" 하고 슬쩍 정정해줬을 때 머쓱했다.면접 끝나고 집에 와서 다시 정리해본 내용을 적는다. 이미 잘 아시는 분들에게는 새로울 게 없을 수 있는데, 저처럼 처음에는 같은 거라고 생각했던 분이 있다면 도움이 될지도 모르겠다.두 개념은 서로 다른 축을 보고 있다다시 정리하면서 가장 결정적이었던 건 이 한 줄이었다.블로킹/논블로킹은 "지금 기다릴까?" 동기/비동기는 "결과는 언제 받을까?"이 두 질문은 같은 동작을 다른 ..

  • format_list_bulleted 카테고리 없음
  • · 2025. 12. 9.
Redis 캐싱 전략, 그냥 쓰지 말고 설계해서 쓰자

Redis 캐싱 전략, 그냥 쓰지 말고 설계해서 쓰자

“캐시는 어렵지 않은데, 잘못 붙이면 더 큰 장애 포인트가 된다.” 이 글을 쓰게 된 계기Spring 기반 백엔드에서 Redis를 캐시 용도로 붙이기 시작했을 때, 솔직히 이렇게 생각했다.“DB 쿼리 전에 Redis 한 번 보고, 없으면 DB 조회해서 넣으면 끝 아닌가?”처음에는 진짜로 그 정도만 해도 성능이 꽤나 좋아졌다.조회 수가 많은 API에 캐시를 한 번 둘러줬더니, DB 커넥션 수가 눈에 띄게 줄고 응답 시간도 안정적으로 떨어졌다.문제는 그다음이었다.캐시 갱신 타이밍이 꼬이면서 유저에게는 이미 삭제된 데이터가 계속 보이고특정 키의 TTL이 한꺼번에 만료되면서 캐시 스탬피드가 터지고여러 서비스에서 같은 Redis를 쓰다 보니 키 충돌과 메모리 압박이 슬슬 보이기 시작했다.그때부터 “그냥 Redis..

  • format_list_bulleted [ 기술 스택 ]/Cache
  • · 2025. 12. 8.
  • navigate_before
  • 1
  • 2
  • 3
  • navigate_next
공지사항
전체 카테고리
  • __ (28)
    • [ 프로젝트 ] (1)
      • MIYOU (0)
      • INSTY (1)
    • [ 기술 스택 ] (12)
      • Webflux (8)
      • ElasticSearch (0)
      • Kafka (0)
      • Security (1)
      • JPA (0)
      • Cache (2)
      • Async & MQ (1)
    • [ 공부 ] (4)
    • [ 트러블슈팅 ] (1)
    • [ 인사이트 ] (3)
인기 글
전체 방문자
오늘
어제
Copyright © Devon 모든 권리 보유.
SKIN: Copyright © 쭈미로운 생활 All rights reserved. Designed by JJuum.
and Current skin "dev-roo" is modified by Jin.

티스토리툴바