์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค์ด์ค๋ ๋ฐ์ดํฐ๊ฐ ์ฌ๋ฐ๋ฅธ์ง ํ์ธํ๋ ๊ณผ์
๋จ์ํ null ์ฒดํฌ๋ง ํ๋ ๊ฒ ์๋๋ผ
๐ ๋ค์ํ ์์ค์ ๊ฒ์ฆ์ด ์กด์ฌํจ
ํ ๊ตฐ๋ฐ์์๋ง ๊ฒ์ฆํ๋ฉด?
๐ ๋ค๋ฅธ ๊ฒฝ๋ก์์ ๋ค์ด์ค๋ ๋ฐ์ดํฐ๋ ๋ฐฉ์ด ๋ชป ํจ
๋ฐ๋๋ก ๋ชจ๋ ๊ณ์ธต์์ ๊ฒ์ฆํ๋ฉด?
๐ ์ค๋ณต ์ฝ๋ ์ฆ๊ฐ
๐ ์ ์ง๋ณด์ ์ด๋ ค์
๐ ๊ทธ๋์ ์ฑ ์์ ๋๋ ์ผ ํจ
"์ฌ์ฉ์๊ฐ ๋ณด๋ธ ๊ฐ์ด ์ ์์ ์ธ ํํ์ธ๊ฐ?"
public record CreateUserRequestDTO(
@NotBlank String email,
@NotBlank String username
) {}
โ๏ธ ์ญํ
null, ๊ณต๋ฐฑ ์ฒดํฌ
ํ์ ๊ฒ์ฆ (์ด๋ฉ์ผ, ๊ธธ์ด ๋ฑ)
๐ ๊ฐ์ฅ ๋ฐ๊นฅ์์ 1์ฐจ ํํฐ๋ง
"์ด ๊ฐ์ด ์๋น์ค ๊ท์น์ ๋ง๋๊ฐ?"
if (userRepository.existsByEmail(email)) {
throw new DuplicateEmailException();
}
โ๏ธ ์ญํ
์ค๋ณต ๊ฒ์ฌ
์ํ ๊ฒ์ฆ
๊ถํ ์ฒดํฌ
๐ "์ด๊ฒ ๊ฐ๋ฅํ ์์ฒญ์ธ๊ฐ?"๋ฅผ ํ๋จ
"์ด ๊ฐ์ฒด๋ ํญ์ ์ ํจํ ์ํ์ธ๊ฐ?"
public void changeName(String name) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException();
}
this.name = name;
}
โ๏ธ ์ญํ
๊ฐ์ฒด ์์ฒด์ ์ ํจ์ฑ ์ ์ง
์๋ชป๋ ์ํ ์์ฑ ๋ฐฉ์ง
๐ ๋ง์ง๋ง ๋ฐฉ์ด์
๐ฅ ์ค๋ณต ๊ฒ์ฆ ์์ด ์์ ์ฑ ํ๋ณดํ๋ ๋ฐฉ๋ฒ
๐ ํต์ฌ ์ ๋ต
Controller โ "ํ์ ๊ฒ์ฆ"
Service โ "๋น์ฆ๋์ค ๊ฒ์ฆ"
Entity โ "๋ถ๋ณ์ฑ ๋ณด์ฅ"
๐ ๊ฐ์ ๊ฒ์ฆ์ ์ฌ๋ฌ ๋ฒ ํ์ง ์๋๋ค
์์ โ (์๋ชป๋ ๊ตฌ์กฐ)
Controller์์ null ์ฒดํฌ
Service์์๋ null ์ฒดํฌ
Entity์์๋ null ์ฒดํฌ
๐ ์์ ์ค๋ณต
์์ โญ
Controller: @NotBlank
Service: ์ค๋ณต ์ด๋ฉ์ผ ๊ฒ์ฌ
Entity: ์ํ ๋ณด์ฅ
๐ ์ญํ ๋ถ๋ฆฌ ์๋ฃ
๊ฒ์ฆ์ ์ค์ด๋ฉด โ ์ฝ๋ ๊น๋ ๐
๊ฒ์ฆ์ ๋๋ฆฌ๋ฉด โ ์์ ์ฑ โ ๐
๐ ์ ํ ํ์
๊ฐํ๊ฒ ํ๋ฉด โ ์์ ๐
๋๋ฌด ๊ฐํ๋ฉด โ ์ ์ฐ์ฑ โ ๐
๐ DTO โ Service โ Entity ํ๋ฆ ์ค์
๊ฒ์ฆ ๋ง์ผ๋ฉด โ ์์ ๐
ํ์ง๋ง โ ๋น์ฉ ์ฆ๊ฐ ๐
๐ "ํ์ํ ๋งํผ๋ง"
์ ๋ ฅ๊ฐ ๊ฒ์ฆ = ๊ณ์ธต๋ณ ์ญํ ๋ถ๋ฆฌ
Controller โ ํ์ ๊ฒ์ฆ
Service โ ๋น์ฆ๋์ค ๊ฒ์ฆ
Entity โ ์ํ ๋ณด์ฅ
ํต์ฌ ๐ ์ค๋ณต ์์ด ์ฑ
์ ๋ถ๋ฆฌ
ํธ๋ ์ด๋์คํ ๐ ์์ ์ฑ vs ๋ณต์ก๋
ํ ์คํธ์์ ์ค์ ๊ฐ์ฒด ๋์ ๊ฐ์ง ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
๐ ์ธ๋ถ ์์กด์ฑ์ ์ ๊ฑฐํ๊ณ ํ ์คํธ๋ฅผ ์ฝ๊ฒ ๋ง๋ค์ด์ค
์๋ฅผ ๋ค์ด Service๋ฅผ ํ ์คํธํ ๋
DB ์ ๊ทผ
API ํธ์ถ
๐ ์ด๋ฐ ๊ฒ๊น์ง ๊ฐ์ด ํ ์คํธํ๋ฉด
๋๋ฆผ
๋ถ์์
ํ
์คํธ ์ด๋ ค์
๐ ๊ทธ๋์ ๊ฐ์ง ๊ฐ์ฒด ์ฌ์ฉ
ํ๋์ ์ง์ ์ ์ํ๋ ๊ฐ์ง ๊ฐ์ฒด
UserRepository userRepository = mock(UserRepository.class);
when(userRepository.findById(1L))
.thenReturn(Optional.of(user));
โ๏ธ ํน์ง
์๋ฌด ๋์๋ ์ ํจ
์ฐ๋ฆฌ๊ฐ ์ ์ํ ๋๋ก๋ง ๋์
๐ ์์ ํ ๊ฐ์ง
ํน์ ์ ๋ ฅ์ ๋ํด ๋ฏธ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ์ ํด๋ ๊ฒ
when(userRepository.existsByEmail("test@test.com"))
.thenReturn(true);
โ๏ธ ํน์ง
"์ด ๊ฐ ๋ฃ์ผ๋ฉด ์ด ๊ฒฐ๊ณผ ๋ฐํ"
๐ Mock์ ์ฌ์ฉ ๋ฐฉ์ ์ค ํ๋
์ค์ ๊ฐ์ฒด + ์ผ๋ถ๋ง ๊ฐ์ง๋ก ๋ฎ์ด์ฐ๊ธฐ
List<String> list = spy(new ArrayList<>());
list.add("A"); // ์ค์ ๋์
doReturn(100).when(list).size(); // ์ผ๋ถ๋ง ์กฐ์
โ๏ธ ํน์ง
์ค์ ๋ก์ง ์คํ๋จ
์ผ๋ถ๋ง override ๊ฐ๋ฅ
๐ ๋ฐ์ฏค ์ง์ง
๐ ์ธ๋ถ ์์กด์ฑ ์ ๊ฑฐํ ๋
์์
Repository
API Client
when(userRepository.findById(1L)).thenReturn(user);
๐ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ
๐ "๊ฒฐ๊ณผ๋ง ํ์ํ ๋"
์์
์กฐ๊ฑด ๋ถ๊ธฐ ํ ์คํธ
when(repo.existsByEmail(email)).thenReturn(true);
๐ ๋ก์ง ํ๋ฆ ๊ฒ์ฆ
๐ ์ผ๋ถ๋ง ํ ์คํธํ๊ณ ์ถ์ ๋
์์
๋ณต์กํ ๊ฐ์ฒด
์ค์ ๋ก์ง ์ผ๋ถ ์ ์ง
๐ ํ์ง๋ง
โ ๏ธ ๋จ์ฉ ๊ธ์ง
โ ํ
์คํธ๊ฐ ๋ณต์กํด์ง
๋น ๋ฅด๊ณ ํธํจ ๐
ํ์ง๋ง ์ค์ ์ ๋ค๋ฅผ ์ ์์ ๐
ํ์ค์ ๐
ํ์ง๋ง ์์ธก ์ด๋ ค์ ๐
์ดํด ์ฌ์ ๐
ํ์ง๋ง ํ
์คํธ ๋ฒ์ ์ ํ ๐
Mock / Stub / Spy ์ฐจ์ด
Mock โ ์์ ๊ฐ์ง
Stub โ ๊ฒฐ๊ณผ ์ ์
Spy โ ์ผ๋ถ๋ง ๊ฐ์ง
ํต์ฌ ๐ ์ํฉ์ ๋ง๊ฒ ์ ํ