test: 글 대표 이미지 업로드 Feature 테스트 (#103) - #105
Conversation
#95 에서 아바타에만 적용했던 UploadStorage seam 을 두 번째 업로드 지점으로 넓힌다. 그때 범위를 좁힌 이유가 "테스트 없는 리팩터링을 남기지 않기 위해서"였으니 이번에는 리팩터링과 테스트를 같이 담는다. 썸네일 생성은 seam 밖에 남겼다. 가짜 저장기가 copy() 로 진짜 파일을 만들기 때문에 service('image') 가 실제 GD 로 돌고 결과(400x250)까지 검증할 수 있다. 썸네일까지 가짜 안에 넣었다면 이슈가 요구한 검증이 통째로 사라진다. 테스트를 쓰다 실제 버그가 나왔다: Posts::delete() 가 deleteImageFiles() 를 아예 부르지 않아, 글은 영구 삭제되는데(소프트 삭제가 아니다) 원본과 썸네일이 디스크에 영원히 남았다. 호출부는 create/update 의 롤백·교체 세 곳뿐이었다. 행을 지운 뒤 파일을 정리하도록 고쳤다(update() 와 같은 순서). CI 안전성 확인: service('image') 기본 핸들러는 gd 이고 CI 워크플로도 gd 를 설치한다. imagick 이 기본이었다면 로컬 통과·CI 실패가 났을 것이다. 뮤테이션 4건 확인: - 썸네일 생성 제거 → 업로드·삭제 테스트 - 썸네일 크기 변경 → 업로드 테스트만(존재 여부로는 못 잡는 것을 증명) - 정리에서 썸네일 제외 → 교체·삭제 테스트 - 삭제 시 파일 정리 제거 → 삭제 테스트만 280/280. Closes #103 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Walkthrough게시물 대표 이미지 저장이 Changes게시물 대표 이미지 처리
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/Controllers/Posts.php`:
- Around line 369-374: Handle the return value of $model->delete($id) in the
surrounding delete action before calling deleteImageFiles($image). If the
database deletion fails, skip file cleanup and return the action’s existing
error response; only invoke deleteImageFiles after a successful row deletion.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 54a0dd22-d73f-495b-98e4-7cfa01e9ddaf
📒 Files selected for processing (2)
app/Controllers/Posts.phptests/Feature/PostImageUploadTest.php
CodeRabbit Major 지적. 앞 커밋이 추가한 파일 정리를 delete() 결과와 무관하게 실행하고 있었다. Model::delete() 는 doDelete() 결과를 그대로 돌려주므로 DBDebug=false 에서는 실패가 falsy 로 온다. 그때 파일만 지우면 글은 남은 채 이미지 참조만 깨진다. 삭제 성공을 확인한 뒤에 파일을 정리하고, 실패하면 오류 플래시로 되돌린다. 전에는 실패해도 "글이 삭제되었습니다" 가 나갔다. 이 실패 분기는 Feature 테스트로 태울 수 없다(DB 오류를 만들어야 한다) — #99 의 동시 취소 레이스 분기와 같은 성격이다. 성공 경로의 정리 순서는 testDeletingPostRemovesImageAndThumbnail 이 계속 지킨다. 280/280. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Major 지적 반영했습니다(
삭제 성공을 확인한 뒤 파일을 정리하고, 실패하면 오류 플래시로 되돌립니다 — 전에는 실패해도 "글이 삭제되었습니다" 가 나갔습니다. 이 실패 분기는 Feature 테스트로 태울 수 없습니다(DB 오류를 만들어야 합니다). #99 의 동시 취소 레이스 분기와 같은 성격이라, 덮지 못한다는 사실을 남겨 둡니다. 성공 경로의 정리 순서는 280/280. |
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
#95(PR #102)에서 아바타에만 적용했던
UploadStorageseam 을 두 번째 업로드 지점으로 넓힙니다. 그때 범위를 좁힌 이유가 "테스트 없는 리팩터링을 남기지 않기 위해서"였으니, 이번에는 리팩터링과 테스트를 같은 PR 에 담습니다.썸네일은 seam 밖에 남겼습니다
썸네일까지 seam 안으로 넣으면 가짜가 그 일을 대신하게 되어 썸네일 생성이 테스트에서 통째로 빠집니다 — 이슈가 요구한 항목이 사라집니다.
FakeUploadStorage가copy()로 진짜 파일을 만들기 때문에, 밖에 두면service('image')가 실제 GD 로 돌고 그 결과까지 검증됩니다.테스트를 쓰다 버그가 나왔습니다
Posts::delete()가deleteImageFiles()를 아예 부르지 않았습니다. 호출부는create()·update()의 롤백·교체 세 곳뿐이었습니다. 소프트 삭제도 아니어서($useSoftDeletes없음) 글은 영구 삭제되는데 원본과 썸네일은 디스크에 영원히 남았습니다.이슈 #103 이 "글 삭제 시 원본·썸네일이 함께 지워지는지"를 확인 항목으로 지목했는데, 확인해 보니 구현 자체가 없었습니다. 행을 지운 뒤 파일을 정리하도록 고쳤습니다(
update()와 같은 순서 — 실패 시 살아 있는 글의 이미지를 날리지 않기 위해).CI 안전성
service('image')의 기본 핸들러는gd이고(app/Config/Images.php:14), CI 워크플로도extensions: intl, mbstring, sqlite3, curl, gd로 gd 를 설치합니다. 기본이 imagick 이었다면 CI 에는 없어서 로컬 통과·CI 실패가 났을 것이라, 착수 전에 확인했습니다.테스트 5건
posts.image저장, 원본 존재,thumb_생성 + 실제 400×250image/jpeg위장썸네일은 존재 여부만 보지 않고
getimagesize()로 크기를 확인합니다. 픽스처도 640×480 으로 만들어 실제로 크롭이 일어나게 했습니다.확인
280/280. 뮤테이션 4건:
thumb_제외#95에서 데인 함정도 반영했습니다 —injectMock('uploadstorage', …)소문자, tearDown 에서$_FILES비우기 + 서비스 리셋,tempnam()반환값에 확장자 덧붙이지 않기. 실행 전후writable/uploads파일 수가 같은 것도 확인했습니다.덮지 못하는 것
move_uploaded_file()호출 한 줄(프레임워크 코드). #102 와 같습니다.Closes #103
Summary by CodeRabbit
개선 사항
테스트