Skip to content

test: 글 대표 이미지 업로드 Feature 테스트 (#103) - #105

Merged
nambak merged 2 commits into
mainfrom
test/post-image-upload
Jul 22, 2026
Merged

test: 글 대표 이미지 업로드 Feature 테스트 (#103)#105
nambak merged 2 commits into
mainfrom
test/post-image-upload

Conversation

@nambak

@nambak nambak commented Jul 22, 2026

Copy link
Copy Markdown
Owner

#95(PR #102)에서 아바타에만 적용했던 UploadStorage seam 을 두 번째 업로드 지점으로 넓힙니다. 그때 범위를 좁힌 이유가 "테스트 없는 리팩터링을 남기지 않기 위해서"였으니, 이번에는 리팩터링과 테스트를 같은 PR 에 담습니다.

썸네일은 seam 밖에 남겼습니다

-        $name = $file->getRandomName();
-        $file->move($dir, $name);
+        $name = service('uploadStorage')->store($file);

         service('image')->withFile($dir . '/' . $name)->fit(400, 250, 'center')->save($dir . '/thumb_' . $name);

썸네일까지 seam 안으로 넣으면 가짜가 그 일을 대신하게 되어 썸네일 생성이 테스트에서 통째로 빠집니다 — 이슈가 요구한 항목이 사라집니다. FakeUploadStoragecopy() 로 진짜 파일을 만들기 때문에, 밖에 두면 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×250
텍스트가 image/jpeg 위장 검증 실패 · 저장 없음 · 글도 안 생김
용량 초과(신고 3MB) 위와 동일
수정으로 이미지 교체 옛 원본·썸네일 삭제, 새 것 존재
글 삭제 원본·썸네일 둘 다 삭제

썸네일은 존재 여부만 보지 않고 getimagesize() 로 크기를 확인합니다. 픽스처도 640×480 으로 만들어 실제로 크롭이 일어나게 했습니다.

확인

280/280. 뮤테이션 4건:

뮤테이션 실패한 테스트
썸네일 생성 제거 업로드·삭제
썸네일 크기 400×250 → 200×200 업로드만 — 존재 여부로는 못 잡는 회귀를 크기 단언이 잡는다는 증거
정리에서 thumb_ 제외 교체·삭제
삭제 시 파일 정리 제거 삭제만

#95 에서 데인 함정도 반영했습니다 — injectMock('uploadstorage', …) 소문자, tearDown 에서 $_FILES 비우기 + 서비스 리셋, tempnam() 반환값에 확장자 덧붙이지 않기. 실행 전후 writable/uploads 파일 수가 같은 것도 확인했습니다.

덮지 못하는 것

move_uploaded_file() 호출 한 줄(프레임워크 코드). #102 와 같습니다.

Closes #103

Summary by CodeRabbit

  • 개선 사항

    • 게시물 대표 이미지 업로드 저장 방식을 개선하여 안정적으로 처리되도록 했습니다.
    • 업로드 후 원본 이미지와 400×250 크기 썸네일이 함께 생성됩니다.
    • 이미지가 아니거나 용량 제한을 초과한 파일은 저장되지 않습니다.
    • 대표 이미지를 교체하면 이전 원본 이미지와 썸네일이 함께 삭제됩니다.
    • 게시물 삭제 시 연결된 원본 이미지와 썸네일도 함께 정리됩니다.
  • 테스트

    • 업로드/검증/교체/삭제 전 과정을 검증하는 통합 테스트를 추가했습니다.

#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>
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a05bf578-078c-41cc-b56f-6f790b09c550

📥 Commits

Reviewing files that changed from the base of the PR and between f9cc2b6 and 01d594b.

📒 Files selected for processing (1)
  • app/Controllers/Posts.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/Controllers/Posts.php

Walkthrough

게시물 대표 이미지 저장이 uploadStorage 서비스 기반으로 변경되었으며, 업로드 검증·썸네일 생성·이미지 교체 및 게시물 삭제 시 파일 정리를 Feature 테스트로 추가했다.

Changes

게시물 대표 이미지 처리

Layer / File(s) Summary
UploadStorage 기반 저장 및 업로드 검증
app/Controllers/Posts.php, tests/Feature/PostImageUploadTest.php
대표 이미지 저장을 uploadStorage->store()로 위임하고, 정상 이미지의 원본·400x250 썸네일 생성과 잘못된 형식 및 크기 초과 업로드 거부를 검증한다.
이미지 교체 및 삭제 정리
app/Controllers/Posts.php, tests/Feature/PostImageUploadTest.php
게시물 삭제 성공 후 저장된 이미지와 썸네일을 제거하도록 흐름을 변경하고, 이미지 교체 및 게시물 삭제 시 파일 정리를 검증한다.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • nambak/ci4blog#57: 대표 이미지 저장·썸네일 처리와 관련 테스트를 직접 변경한 선행 작업입니다.
  • nambak/ci4blog#102: UploadStorage seam과 FakeUploadStorage를 아바타 업로드에 적용한 관련 변경입니다.

Poem

당근처럼 파일이 쏙 저장되고
썸네일도 깔끔히 자라네.
낡은 그림은 살포시 지우고
새 그림은 반짝반짝!
토끼도 귀를 쫑긋, 테스트 완료 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 글 대표 이미지 업로드 Feature 테스트 추가라는 핵심 변경을 간결하게 잘 요약합니다.
Linked Issues check ✅ Passed [#103] UploadStorage seam 적용, Feature 테스트 추가, 썸네일 검증, 삭제 시 파일 정리까지 요구사항을 충족합니다.
Out of Scope Changes check ✅ Passed 삭제 실패 시 파일을 보존하는 보완은 대표 이미지 삭제 정합성을 위한 범위 내 변경입니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/post-image-upload

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nambak

nambak commented Jul 22, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nambak

nambak commented Jul 22, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 7e0f72b and f9cc2b6.

📒 Files selected for processing (2)
  • app/Controllers/Posts.php
  • tests/Feature/PostImageUploadTest.php

Comment thread app/Controllers/Posts.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>
@nambak

nambak commented Jul 22, 2026

Copy link
Copy Markdown
Owner Author

Major 지적 반영했습니다(01d594b). 타당했습니다.

Model::delete()doDelete() 결과를 그대로 돌려주므로 DBDebug=false 에서는 실패가 falsy 로 옵니다. 앞 커밋이 추가한 파일 정리가 그 결과와 무관하게 실행되고 있었고, 그러면 글은 남은 채 이미지 참조만 깨집니다. 제가 추가한 줄이 만든 문제라 이 PR 범위 안이 맞습니다.

삭제 성공을 확인한 뒤 파일을 정리하고, 실패하면 오류 플래시로 되돌립니다 — 전에는 실패해도 "글이 삭제되었습니다" 가 나갔습니다.

이 실패 분기는 Feature 테스트로 태울 수 없습니다(DB 오류를 만들어야 합니다). #99 의 동시 취소 레이스 분기와 같은 성격이라, 덮지 못한다는 사실을 남겨 둡니다. 성공 경로의 정리 순서는 testDeletingPostRemovesImageAndThumbnail 이 계속 지킵니다.

280/280.

@nambak

nambak commented Jul 22, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nambak

nambak commented Jul 22, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nambak
nambak merged commit a044b37 into main Jul 22, 2026
1 check passed
@nambak
nambak deleted the test/post-image-upload branch July 22, 2026 11:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

글 대표 이미지 업로드에 UploadStorage seam 적용 + Feature 테스트

1 participant