Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
Expand All @@ -19,6 +20,7 @@
import java.util.Arrays;

@Configuration
@Profile("!test")
@EnableRedisHttpSession
public class RedisConfig {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("!test")
Copy link
Contributor

Choose a reason for hiding this comment

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

RedissonConfig에 @Profile("!test")를 사용한 이유가
테스트 코드 작성시에 RedissonConfig를 Mock으로 사용하기 위함인가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

네 이걸 사용하지 않으면 springboottest 시작시 테스트로 만든 것이 기존의 confiquration과 겹치거나 무시되서 사용했습니다.

public class RedissonConfig {


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public LocalContainerEntityManagerFactoryBean shopEntityManager() {
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());

Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "update");
properties.put("hibernate.hbm2ddl.auto", "create-drop");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
properties.setProperty("hibernate.physical_naming_strategy",
"org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package com.jishop.config;

import lombok.Getter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.jishop.saleproduct.domain.SaleProduct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
Expand Down Expand Up @@ -47,7 +48,6 @@ public Long createReview(ReviewRequest reviewRequest, User user) {

SaleProduct saleProduct = orderDetail.getSaleProduct();

String productSummary = makeProductSummar(saleProduct, orderDetail);

Product product = saleProduct.getProduct();

Expand All @@ -64,10 +64,14 @@ public Long createReview(ReviewRequest reviewRequest, User user) {

reviewProduct.increaseRating(reviewRequest.rating());

// 리뷰 저장
Review review = reviewRepository.save(reviewRequest.toEntity(reviewRequest.images(), product, orderDetail, user, productSummary));
String productSummary = makeProductSummar(saleProduct, orderDetail);

return review.getId();
try {
Review review = reviewRepository.save(reviewRequest.toEntity(reviewRequest.images(), product, orderDetail, user, productSummary));
return review.getId();
} catch (DataIntegrityViolationException e) {
throw new DomainException(ErrorType.REVIEW_DUPLICATE);
}
}

private String makeProductSummar(SaleProduct saleProduct, OrderDetail orderDetail) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.jishop.config;

import org.redisson.api.RedissonClient;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

import static org.mockito.Mockito.mock;

@TestConfiguration
public class TestRedisConfig {
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return mock(RedisConnectionFactory.class);
}

@Bean
public RedisTemplate<?, ?> redisTemplate() {
RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory()); // 이렇게 factory 연결
return redisTemplate;
}

@Bean
public RedissonClient redissonClient() {
return mock(RedissonClient.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
package com.jishop.review;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.jishop.address.dto.AddressRequest;
import com.jishop.category.domain.Category;
import com.jishop.category.repository.CategoryRepository;
import com.jishop.config.TestRedisConfig;
import com.jishop.member.annotation.CurrentUserResolver;
import com.jishop.member.domain.LoginType;
import com.jishop.member.domain.User;
import com.jishop.member.repository.UserRepository;
import com.jishop.option.domain.Option;
import com.jishop.option.domain.OptionCategory;
import com.jishop.option.repository.OptionRepository;
import com.jishop.order.domain.Order;
import com.jishop.order.domain.OrderDetail;
import com.jishop.order.dto.OrderDetailRequest;
import com.jishop.order.dto.OrderRequest;
import com.jishop.order.repository.OrderRepository;
import com.jishop.product.domain.DiscountStatus;
import com.jishop.product.domain.Labels;
import com.jishop.product.domain.Product;
import com.jishop.product.domain.SaleStatus;
import com.jishop.product.repository.ProductRepository;
import com.jishop.review.domain.tag.Tag;
import com.jishop.review.dto.ReviewRequest;
import com.jishop.review.service.ReviewService;
import com.jishop.saleproduct.domain.SaleProduct;
import com.jishop.saleproduct.repository.SaleProductRepository;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@Transactional
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
@Import(TestRedisConfig.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class ReviewIntegrationTest {

@Autowired
private SaleProductRepository saleProductRepository;

@Autowired
private OptionRepository optionRepository;

@Autowired
private ReviewService reviewService;

@Autowired
private CategoryRepository categoryRepository;

@Autowired
private ProductRepository productRepository;

@Autowired
private OrderRepository orderRepository;

@Autowired
private UserRepository userRepository;

@Autowired
private MockMvc mvc;

@Autowired
private ObjectMapper objectMapper;

@MockitoBean
private CurrentUserResolver currentUserResolver;

@BeforeAll
void init() {
Category category = new Category(null, 5000L, "패션", "5000", "패션", 1);
Category category1 = new Category(category, 5010L, "상의", "5000>5010", "패션>상의", 2);
Category category2 = new Category(category1, 5100L, "점퍼", "5000>5010>5100", "패션>상의>점퍼", 3);
categoryRepository.save(category);
categoryRepository.save(category1);
categoryRepository.save(category2);

Product product = new Product(category, 5000L, 5010L, 5100L, "MALL-001", "테스트 상품", "테스트 상품 설명", 10000, 8000, 20, LocalDateTime.now()
, false, SaleStatus.SELLING, DiscountStatus.NONE, true, "테스트 브랜드", 0, Labels.SPECIAL_PRICE,
"main.jpg", "image1.jpg", "image2.jpg", "image3.jpg", "image4.jpg", "detail.jpg", 0);

productRepository.save(product);

Option option = new Option(OptionCategory.FASHION_CLOTHES, "화이트/FREE", 1000);
optionRepository.save(option);

SaleProduct saleProduct = new SaleProduct(product, option, "화이트 점퍼");
saleProductRepository.save(saleProduct);


OrderRequest sampleOrderRequest = createSampleOrderRequest();

User user = User.builder()
.loginId("testuser@example.com") // 로그인 아이디 (이메일 또는 소셜 ID)
.password("testPassword123!") // 비밀번호 (소셜 로그인은 null 가능)
.name("홍길동") // 이름
.birthDate("1995-05-01") // 생년월일
.gender("M") // 성별 (M/F)
.phone("010-1234-5678") // 휴대폰 번호
.provider(LoginType.LOCAL) // 로그인 타입 (enum 값)
.ageAgreement(true) // 만 14세 이상 동의
.useAgreement(true) // 서비스 이용 약관 동의
.picAgreement(true) // 개인정보 처리 방침 동의
.adAgreement(false) // 광고 수신 동의
.build();
Comment on lines +113 to +125
Copy link
Contributor

Choose a reason for hiding this comment

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

이런 코드에서는 fixture를 사용하는 방법도 있다고 알고있는데, 어떻게 생각하시나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixture 사용은 추후에 사용할 예정입니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

아직 다른 곳에서 재사용하지 않아서 필요시 만들 예정입니다.


userRepository.save(user);

Order order = Order.from(sampleOrderRequest, user, "1");
OrderDetail orderDetail = OrderDetail.from(order, saleProduct, 3);
List<OrderDetail> list = new ArrayList<>();
list.add(orderDetail);
order.updateOrderInfo(1000, 0, 1000, list, "1");
orderRepository.save(order);


}

@Test
@DisplayName("리뷰 작성")
void createReview() throws Exception {
// given
ReviewRequest request = new ReviewRequest(1L, "굳굳", null, Tag.RECOMMENDED, 3);
User user = userRepository.findById(1L).orElseThrow(IllegalStateException::new);
loginResolver(user);

// when
Long result = 리뷰작성(request);

// then
Assertions.assertNotNull(result);
Copy link
Contributor

Choose a reason for hiding this comment

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

여기서 리뷰가 null인지만 체크하면 좀 부족하지 않을까요 내용이 예상대로 들어갔는지 같은 좀 더 구체적인 검증이 추가되면 어떨까요?

Copy link
Contributor Author

@jihaneol jihaneol Apr 15, 2025

Choose a reason for hiding this comment

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

오 좋습니다! 감사합니다!

}


@Test
@DisplayName("한번한 리뷰 작성 또 작성할때 에러 발생.")
void duplicate_review() throws Exception {
// given
ReviewRequest request = new ReviewRequest(1L, "굳굳", null, Tag.RECOMMENDED, 3);
User user = userRepository.findById(1L).orElseThrow(IllegalStateException::new);
loginResolver(user);
리뷰작성(request);

//when
mvc.perform(MockMvcRequestBuilders.post("/reviews")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isConflict());
}


private OrderRequest createSampleOrderRequest() {
// 주소 정보 생성
AddressRequest addressRequest = new AddressRequest(
"홍길동",
"010-1234-5678",
"12345",
"서울특별시 강남구 테헤란로 123",
"456동 789호",
false
);

// 주문 상품 목록 생성
List<OrderDetailRequest> orderDetailRequestList = List.of(
new OrderDetailRequest(1L, 3) // saleProductId: 1, quantity: 3
);

// OrderRequest 객체 생성 및 반환
return new OrderRequest(addressRequest, orderDetailRequestList);
}

private void loginResolver(User user) throws Exception {
given(currentUserResolver.supportsParameter(any()))
.willReturn(true);
given(currentUserResolver.resolveArgument(any(), any(), any(), any()))
.willReturn(user);// 강제 리턴
}


private Long 리뷰작성(ReviewRequest request) throws Exception {
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.post("/reviews")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isOk())
.andReturn();

String response = mvcResult.getResponse().getContentAsString();

return objectMapper.readValue(response, Long.class);
}
}
16 changes: 0 additions & 16 deletions backend/JiShop/src/test/java/com/jishop/review/dtoTest.java

This file was deleted.

This file was deleted.

Loading