Skip to content

Commit 25b423e

Browse files
committed
feat(brand): 브랜드 도메인 모델 및 도메인 서비스 구현
- Brand 엔티티 생성 및 도메인 검증 로직 추가 - BrandRepository 인터페이스 정의 - Brand 도메인 서비스 설계 - Brand 단위/통합 테스트 작성 (생성/검증)
1 parent 4fda674 commit 25b423e

6 files changed

Lines changed: 202 additions & 0 deletions

File tree

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.loopers.domain.brand;
2+
3+
import com.loopers.support.error.CoreException;
4+
import com.loopers.support.error.ErrorType;
5+
import jakarta.persistence.*;
6+
import lombok.Getter;
7+
8+
/**
9+
* packageName : com.loopers.domain.brand
10+
* fileName : Brand
11+
* author : byeonsungmun
12+
* date : 2025. 11. 11.
13+
* description :
14+
* ===========================================
15+
* DATE AUTHOR NOTE
16+
* -------------------------------------------
17+
* 2025. 11. 11. byeonsungmun 최초 생성
18+
*/
19+
@Entity
20+
@Table(name = "brand")
21+
@Getter
22+
public class Brand {
23+
@Id
24+
@GeneratedValue(strategy = GenerationType.IDENTITY)
25+
private Long id;
26+
27+
@Column(nullable = false)
28+
private String name;
29+
30+
protected Brand() {}
31+
32+
private Brand(String name) {
33+
this.name = requireValidName(name);
34+
}
35+
36+
public static Brand create(String name) {
37+
return new Brand(name);
38+
}
39+
40+
41+
private String requireValidName(String name) {
42+
if (name == null || name.isEmpty()) {
43+
throw new CoreException(ErrorType.BAD_REQUEST, "상품명 비어 있을수 없습니다.");
44+
}
45+
return name.trim();
46+
}
47+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.loopers.domain.brand;
2+
3+
import java.util.Optional;
4+
5+
/**
6+
* packageName : com.loopers.domain.brand
7+
* fileName : BrandRepository
8+
* author : byeonsungmun
9+
* date : 2025. 11. 12.
10+
* description :
11+
* ===========================================
12+
* DATE AUTHOR NOTE
13+
* -------------------------------------------
14+
* 2025. 11. 12. byeonsungmun 최초 생성
15+
*/
16+
public interface BrandRepository {
17+
Optional<Brand> findById(Long id);
18+
19+
void save(Brand brand);
20+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.loopers.domain.brand;
2+
3+
import com.loopers.support.error.CoreException;
4+
import com.loopers.support.error.ErrorType;
5+
import lombok.RequiredArgsConstructor;
6+
import org.springframework.stereotype.Component;
7+
import org.springframework.transaction.annotation.Transactional;
8+
9+
/**
10+
* packageName : com.loopers.domain.brand
11+
* fileName : BrandService
12+
* author : byeonsungmun
13+
* date : 2025. 11. 12.
14+
* description :
15+
* ===========================================
16+
* DATE AUTHOR NOTE
17+
* -------------------------------------------
18+
* 2025. 11. 12. byeonsungmun 최초 생성
19+
*/
20+
@Component
21+
@RequiredArgsConstructor
22+
public class BrandService {
23+
24+
private final BrandRepository brandRepository;
25+
26+
@Transactional
27+
public void save(Brand brand) {
28+
brandRepository.save(brand);
29+
}
30+
31+
@Transactional(readOnly = true)
32+
public Brand getBrand(Long id) {
33+
return brandRepository.findById(id)
34+
.orElseThrow(() -> new CoreException(ErrorType.NOT_FOUND, "브랜드를 찾을 수 없습니다."));
35+
}
36+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.loopers.infrastructure.brand;
2+
3+
import com.loopers.domain.brand.Brand;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
import java.util.Optional;
7+
8+
/**
9+
* packageName : com.loopers.infrastructure.brand
10+
* fileName : BrandJpaRepository
11+
* author : byeonsungmun
12+
* date : 2025. 11. 12.
13+
* description :
14+
* ===========================================
15+
* DATE AUTHOR NOTE
16+
* -------------------------------------------
17+
* 2025. 11. 12. byeonsungmun 최초 생성
18+
*/
19+
public interface BrandJpaRepository extends JpaRepository<Brand, Long> {
20+
Optional<Brand> findById(Long id);
21+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.loopers.infrastructure.brand;
2+
3+
import com.loopers.domain.brand.Brand;
4+
import com.loopers.domain.brand.BrandRepository;
5+
import lombok.RequiredArgsConstructor;
6+
import org.springframework.stereotype.Component;
7+
8+
import java.util.Optional;
9+
10+
/**
11+
* packageName : com.loopers.infrastructure.brand
12+
* fileName : BrandRepositroyImpl
13+
* author : byeonsungmun
14+
* date : 2025. 11. 12.
15+
* description :
16+
* ===========================================
17+
* DATE AUTHOR NOTE
18+
* -------------------------------------------
19+
* 2025. 11. 12. byeonsungmun 최초 생성
20+
*/
21+
@RequiredArgsConstructor
22+
@Component
23+
public class BrandRepositoryImpl implements BrandRepository {
24+
25+
private final BrandJpaRepository jpaRepository;
26+
27+
@Override
28+
public Optional<Brand> findById(Long id) {
29+
return jpaRepository.findById(id);
30+
}
31+
32+
@Override
33+
public void save(Brand brand) {
34+
jpaRepository.save(brand);
35+
}
36+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.loopers.domain.brand;
2+
3+
import com.loopers.support.error.CoreException;
4+
import org.junit.jupiter.api.DisplayName;
5+
import org.junit.jupiter.api.Nested;
6+
import org.junit.jupiter.api.Test;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
10+
11+
/**
12+
* packageName : com.loopers.domain.brand
13+
* fileName : BrandTest
14+
* author : byeonsungmun
15+
* date : 2025. 11. 14.
16+
* description :
17+
* ===========================================
18+
* DATE AUTHOR NOTE
19+
* -------------------------------------------
20+
* 2025. 11. 14. byeonsungmun 최초 생성
21+
*/
22+
class BrandTest {
23+
24+
@DisplayName("Brand 단위 테스트")
25+
@Nested
26+
class CreateBrandTest {
27+
28+
@Test
29+
@DisplayName("브랜드 생성 성공")
30+
void createBrandSuccess() {
31+
Brand brand = Brand.create("Nike");
32+
assertThat(brand.getName()).isEqualTo("Nike");
33+
}
34+
35+
@Test
36+
@DisplayName("브랜드 이름이 없으면 예외")
37+
void createBrandFail() {
38+
assertThatThrownBy(() -> Brand.create(""))
39+
.isInstanceOf(CoreException.class);
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)