diff --git a/README.md b/README.md index c340c13..1e95b00 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,12 @@ USECASE - 관리자 - 관리자는 회원관리를 위해 구매자/판매자의 상태를 관리 할 수있다. +테스트 +--- +- Mockito Framework를 활용하여 고립된 테스트 코드를 작성 +- Jenkins CI를 적용하여 테스트 자동화 +- 협업하는 동료의 소스코드에 서로 테스트코드를 작성하여 서로의 소스코드를 알 수 있도록 하고 있습니다. + ERD --- ![UsedMarket_24_20200730_39_51](https://user-images.githubusercontent.com/61732452/88840524-98ed7100-d217-11ea-9b76-8043edc17326.png) diff --git a/pom.xml b/pom.xml index 98120af..6c534bf 100644 --- a/pom.xml +++ b/pom.xml @@ -49,12 +49,6 @@ org.springframework.boot spring-boot-starter-test test - - - org.junit.vintage - junit-vintage-engine - - mysql @@ -99,13 +93,6 @@ spring-session-data-redis - - - junit - junit - test - - org.springframework.boot @@ -148,7 +135,6 @@ org.springframework.boot spring-boot-maven-plugin - 2.3.1.RELEASE diff --git a/src/main/java/com/market/server/service/Impl/ProductServiceImpl.java b/src/main/java/com/market/server/service/Impl/ProductServiceImpl.java index 25ed803..e10d149 100644 --- a/src/main/java/com/market/server/service/Impl/ProductServiceImpl.java +++ b/src/main/java/com/market/server/service/Impl/ProductServiceImpl.java @@ -69,6 +69,7 @@ public void updateProducts(ProductDTO productDTO) { public void deleteProduct(int accountId, int productId) { if (accountId != 0 && productId != 0) { productMapper.deleteProduct(accountId, productId); + if(productDao.selectProductsIndex(productId)!=0) productId = productDao.selectProductsIndex(productId); if (productDao.deleteByProductIdAndIndex(ProductDTO.DEFAULT_PRODUCT_SEARCH_CACHE_KEY, productId) == false) { throw new RuntimeException("물품 레디스 리스트에서 삭제 실패!"); diff --git a/src/main/java/com/market/server/utils/DateUtil.java b/src/main/java/com/market/server/utils/DateUtil.java index fe87b11..5a953f1 100644 --- a/src/main/java/com/market/server/utils/DateUtil.java +++ b/src/main/java/com/market/server/utils/DateUtil.java @@ -16,7 +16,7 @@ public class DateUtil { * @return 처리 시간의 문자열 202009040159.jpg * @author topojs8 */ - private static ThreadLocal getNowTimeToyyyyMMddHHmm = new ThreadLocal() { + private static final ThreadLocal getNowTimeToyyyyMMddHHmm = new ThreadLocal() { @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat("yyyyMMddHHmm"); diff --git a/src/main/resources/application-release.properties b/src/main/resources/application-release.properties index 01b618e..5c16669 100644 --- a/src/main/resources/application-release.properties +++ b/src/main/resources/application-release.properties @@ -1,7 +1,7 @@ # mysql -spring.datasource.url=jdbc:mysql://localhost:3307/market?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Seoul -spring.datasource.username=root -spring.datasource.password=wnstjr1026 +spring.datasource.url=jdbc:mysql://10.41.82.248:3306/market?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Seoul +spring.datasource.username=topojs +spring.datasource.password=1234 # message spring.messages.basename=i18n/exception @@ -10,10 +10,14 @@ spring.messages.encoding=UTF-8 # redis spring.cache.type=redis spring.data.redis.repositories.enabled=true -market.server.redis.host=localhost +market.server.redis.host=10.41.83.37 market.server.redis.port=6379 market.server.redis.password= # expire expire.defaultTime=36288000 -expire.products=5 +expire.products=5000 + +#JSP, HTML ModelAndView Path Setting +spring.mvc.view.prefix=/WEB-INF/jsp/ +spring.mvc.view.suffix=.jsp \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 74eaeb3..9fcbca8 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,8 +1,8 @@ # Server -server.port= +server.port=8080 # profile name = local, dev, prod -spring.profiles.active=dev +spring.profiles.active=release # session spring.session.store-type=redis \ No newline at end of file diff --git a/src/test/java/com/market/server/UsedMarketServerApplicationTests.java b/src/test/java/com/market/server/UsedMarketServerApplicationTests.java index 9c640f8..a950c6b 100644 --- a/src/test/java/com/market/server/UsedMarketServerApplicationTests.java +++ b/src/test/java/com/market/server/UsedMarketServerApplicationTests.java @@ -6,7 +6,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; -@RunWith(SpringRunner.class) +//@RunWith(SpringRunner.class) class UsedMarketServerApplicationTests { @Test diff --git a/src/test/java/com/market/server/service/Impl/CategoryServiceImplTest.java b/src/test/java/com/market/server/service/Impl/CategoryServiceImplTest.java new file mode 100644 index 0000000..ddef3c8 --- /dev/null +++ b/src/test/java/com/market/server/service/Impl/CategoryServiceImplTest.java @@ -0,0 +1,64 @@ +package com.market.server.service.Impl; + +import com.market.server.dao.ProductDao; +import com.market.server.dto.CategoryDTO; +import com.market.server.dto.ProductDTO; +import com.market.server.mapper.CategoryMapper; +import com.market.server.mapper.ProductMapper; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Date; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.BDDMockito.given; + +@RunWith(MockitoJUnitRunner.class) +class CategoryServiceImplTest { + + @InjectMocks + CategoryServiceImpl categoryService; + + @Mock + CategoryMapper categoryMapper; + + // 새로운 카테고리 객체를 생성하여 반환한다. + public CategoryDTO generateCategory() { + MockitoAnnotations.initMocks(this); // mock all the field having @Mock annotation + CategoryDTO categoryDTO = CategoryDTO.builder() + .id(1) + .name("testName") + .sortStatus(CategoryDTO.SortStatus.NEWEST) + .searchCount(1000) + .pagingStartOffset(0) + .build(); + return categoryDTO; + } + + @Test + void register() { + CategoryDTO categoryDTO = generateCategory(); + given(categoryMapper.register(categoryDTO)).willReturn(categoryDTO.getId()); + categoryMapper.register(categoryDTO); + } + + @Test + void update() { + CategoryDTO categoryDTO = generateCategory(); + categoryDTO.setName("testName2"); + categoryMapper.updateCategory(categoryDTO); + assertEquals(categoryDTO.getName(),("testName2")); + } + + @Test + void delete() { + CategoryDTO categoryDTO = generateCategory(); + categoryDTO.setId(1); + categoryMapper.deleteCategory(1); + } +} \ No newline at end of file diff --git a/src/test/java/com/market/server/service/Impl/ProductSearchServiceImplTest.java b/src/test/java/com/market/server/service/Impl/ProductSearchServiceImplTest.java new file mode 100644 index 0000000..1ece9c2 --- /dev/null +++ b/src/test/java/com/market/server/service/Impl/ProductSearchServiceImplTest.java @@ -0,0 +1,93 @@ +package com.market.server.service.Impl; + +import com.market.server.dao.ProductDao; +import com.market.server.dto.CategoryDTO; +import com.market.server.dto.ProductDTO; +import com.market.server.dto.UserDTO; +import com.market.server.mapper.ProductMapper; +import com.market.server.utils.SHA256Util; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.BDDMockito.given; + +@RunWith(MockitoJUnitRunner.class) +class ProductSearchServiceImplTest { + + @InjectMocks + ProductServiceImpl productService; + + @InjectMocks + ProductSearchServiceImpl productSearchService; + + @Mock + ProductMapper productMapper; + + @Mock + ProductDao productDao; + + // 새로운 물품 객체 리스트를 생성하여 반환한다. + public List generateProductList() { + MockitoAnnotations.initMocks(this); // mock all the field having @Mock annotation + List productDTOList = new ArrayList(); + for (int i = 0; i < 5; i++) { + ProductDTO productDTO = ProductDTO.builder() + .id(i) + .price(1000) + .accountId(1) + .title("testProductTitle") + .contents("testProductContents") + .status(ProductDTO.Status.NEW) + .istrade(true) + .updatetime(new Date()) + .deliveryprice(3000) + .dibcount(1) + .categoryId(1) + .build(); + productDTOList.add(productDTO); + } + return productDTOList; + } + + public UserDTO generateUser() { + UserDTO userDTO = new UserDTO(); + userDTO.setId("textUserId"); + userDTO.setPassword(SHA256Util.encryptSHA256("testPassword")); + userDTO.setName("testUserName"); + userDTO.setPhone("010-1111-2222"); + userDTO.setAddress("testAdress"); + userDTO.setStatus(UserDTO.Status.DEFAULT); + userDTO.setCreatetime(new Date()); + userDTO.setUpdatetime(new Date()); + userDTO.setAddmin(false); + userDTO.setAccountId(1); + return userDTO; + } + + @Test + void findAllProductsByCacheId() { + MockitoAnnotations.initMocks(this); // mock all the field having @Mock annotation + UserDTO userDTO = generateUser(); + productDao.findAllProductsByCacheId(userDTO.getId()); + } + + @Test + void getProducts() { + List productDTOList = generateProductList(); + given(productMapper.selectMyProducts(1)).willReturn(productDTOList); + given(productMapper.selectMyProducts(999)).willReturn(null); + productMapper.selectMyProducts(1); + + UserDTO userDTO = generateUser(); + productService.getMyProducts(userDTO.getAccountId()); + } +} \ No newline at end of file diff --git a/src/test/java/com/market/server/service/Impl/ProductServiceImplTest.java b/src/test/java/com/market/server/service/Impl/ProductServiceImplTest.java new file mode 100644 index 0000000..a0cf3df --- /dev/null +++ b/src/test/java/com/market/server/service/Impl/ProductServiceImplTest.java @@ -0,0 +1,158 @@ +package com.market.server.service.Impl; + +import com.market.server.dao.ProductDao; +import com.market.server.dto.ProductDTO; +import com.market.server.dto.UserDTO; +import com.market.server.mapper.ProductMapper; +import com.market.server.mapper.ProductSearchMapper; +import com.market.server.mapper.UserProfileMapper; +import com.market.server.utils.SHA256Util; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.mockito.*; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.BDDMockito.given; + +@RunWith(MockitoJUnitRunner.class) +class ProductServiceImplTest { + + @InjectMocks + ProductServiceImpl productService; + + @Mock + ProductMapper productMapper; + + @Mock + UserProfileMapper userProfileMapper; + + @Mock + ProductDao productDao; + + @InjectMocks + ProductDao productDaoCache; + + @Mock + ProductSearchMapper productSearchMapper; + + @Mock + private RedisTemplate redisTemplate; + + @Mock + private ValueOperations valueOperations; + + // 새로운 물품 객체를 생성하여 반환한다. + public ProductDTO generateProduct() { + MockitoAnnotations.initMocks(this); // mock all the field having @Mock annotation + ProductDTO productDTO = ProductDTO.builder() + .id(1) + .price(1000) + .accountId(1) + .title("testProductTitle") + .contents("testProductContents") + .status(ProductDTO.Status.NEW) + .istrade(true) + .updatetime(new Date()) + .deliveryprice(3000) + .dibcount(1) + .categoryId(1) + .build(); + return productDTO; + } + + // 새로운 물품 객체 리스트를 생성하여 반환한다. + public List generateProductList() { + MockitoAnnotations.initMocks(this); // mock all the field having @Mock annotation + List productDTOList = new ArrayList(); + for (int i = 0; i < 5; i++) { + ProductDTO productDTO = ProductDTO.builder() + .id(i) + .price(1000) + .accountId(1) + .title("testProductTitle") + .contents("testProductContents") + .status(ProductDTO.Status.NEW) + .istrade(true) + .updatetime(new Date()) + .deliveryprice(3000) + .dibcount(1) + .categoryId(1) + .build(); + productDTOList.add(productDTO); + } + return productDTOList; + } + + public UserDTO generateUser() { + UserDTO userDTO = new UserDTO(); + userDTO.setId("testUserId"); + userDTO.setPassword(SHA256Util.encryptSHA256("testPassword")); + userDTO.setName("testUserName"); + userDTO.setPhone("010-1111-2222"); + userDTO.setAddress("testAdress"); + userDTO.setStatus(UserDTO.Status.DEFAULT); + userDTO.setCreatetime(new Date()); + userDTO.setUpdatetime(new Date()); + userDTO.setAddmin(false); + userDTO.setAccountId(1); + return userDTO; + } + + @Test + void register() { + ProductDTO productDTO = generateProduct(); + given(productMapper.register(productDTO)). + willReturn(productDTO.getId()); + + UserDTO userDTO = generateUser(); + given(userProfileMapper.getUserProfile(userDTO.getId())) + .willReturn(userDTO); + + productService.register(userDTO.getId(), productDTO); + } + + @Test + void getMyProducts() { + List productDTOList = generateProductList(); + given(productMapper.selectMyProducts(1)).willReturn(productDTOList); + given(productMapper.selectMyProducts(999)).willReturn(null); + productMapper.selectMyProducts(1); + + UserDTO userDTO = generateUser(); + + productService.getMyProducts(userDTO.getAccountId()); + } + + @Test + void updateProducts() { + ProductDTO productDTO = generateProduct(); + productDTO.setContents("testProductContentsMapper"); + productMapper.updateProducts(productDTO); + assertTrue(productDTO.getContents().equals("testProductContentsMapper")); + + productDTO.setContents("testProductContentService"); + productService.updateProducts(productDTO); + assertTrue(productDTO.getContents().equals("testProductContentService")); + } + + @Test + void deleteProduct() { + ProductDTO productDTO = generateProduct(); + UserDTO userDTO = generateUser(); + given(userProfileMapper.getUserProfile(userDTO.getId())) + .willReturn(userDTO); + + productMapper.deleteProduct(1, 1); + + // Mock redisTemplate 테스트 + //redisTemplate.opsForList().rightPush(ProductDTO.DEFAULT_PRODUCT_SEARCH_CACHE_KEY, productDTO); + //productService.deleteProduct(userDTO.getAccountId(), productDTO.getId()); + } +} \ No newline at end of file diff --git a/src/test/java/com/market/server/service/Impl/UserServiceImplTest.java b/src/test/java/com/market/server/service/Impl/UserServiceImplTest.java new file mode 100644 index 0000000..cb7ae2c --- /dev/null +++ b/src/test/java/com/market/server/service/Impl/UserServiceImplTest.java @@ -0,0 +1,111 @@ +package com.market.server.service.Impl; + +import com.market.server.dto.UserDTO; +import com.market.server.mapper.UserProfileMapper; +import com.market.server.utils.SHA256Util; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.Date; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.BDDMockito.given; + +@RunWith(MockitoJUnitRunner.class) +class UserServiceImplTest { + /* + * '@Mock'이 붙은 목 객체를 해당 어노테이션이 선언된 객체에 주입할 수 있다. + * Dao객체를 주입하기 위해서는 Dao에 '@Mock'을, Service에' @InjectMocks'를 붙여주어야한다. + */ + @InjectMocks + UserServiceImpl userService; + + @Mock + UserProfileMapper userProfileMapper; + + // 새로운 멤버 객체를 생성하여 반환한다. + public UserDTO generateUser() { + MockitoAnnotations.initMocks(this); // mock all the field having @Mock annotation + UserDTO userDTO = new UserDTO(); + userDTO.setId("textUserId"); + userDTO.setPassword(SHA256Util.encryptSHA256("testPassword")); + userDTO.setName("testUserName"); + userDTO.setPhone("010-1111-2222"); + userDTO.setAddress("testAdress"); + userDTO.setStatus(UserDTO.Status.DEFAULT); + userDTO.setCreatetime(new Date()); + userDTO.setUpdatetime(new Date()); + userDTO.setAddmin(false); + return userDTO; + } + + @Test + public void getUserInfo() { + UserDTO userDTO = generateUser(); + assertTrue("textUserId".equals(userDTO.getId())); + assertTrue("testUserName" == userDTO.getName()); + } + + @Test + void register() { + UserDTO userDTO = generateUser(); + userProfileMapper.register(userDTO); + + } + + @Test + void login() { + UserDTO userDTO = generateUser(); + given(userProfileMapper.findByIdAndPassword("textUserId", + SHA256Util.encryptSHA256("testPassword"))) + .willReturn(userDTO); + assertThat(userService.login("textUserId", "testPassword")).isEqualTo(userDTO); + } + + @Test + void isDuplicatedId() { + UserDTO userDTO = generateUser(); + given(userProfileMapper.idCheck("textUserId")) + .willReturn(1); + given(userProfileMapper.idCheck("textUserId2")) + .willReturn(0); + userService.login(userDTO.getId(), userDTO.getPassword()); + } + + @Test + void updatePassword() { + UserDTO userDTO = generateUser(); + given(userProfileMapper.updatePassword(userDTO)) + .willReturn(1); + given(userProfileMapper.findByIdAndPassword(userDTO.getId(), SHA256Util.encryptSHA256("testPassword"))) + .willReturn(userDTO); + + userService.updatePassword(userDTO.getId(), "testPassword", "1234"); + } + + @Test + void updateAddress() { + UserDTO userDTO = generateUser(); + given(userProfileMapper.updateAddress(userDTO)) + .willReturn(1); + given(userProfileMapper.getUserProfile(userDTO.getId())) + .willReturn(userDTO); + + userService.updateAddress(userDTO.getId(), "testAdress22"); + } + + @Test + void deleteId() { + UserDTO userDTO = generateUser(); + given(userProfileMapper.findByIdAndPassword("textUserId", + SHA256Util.encryptSHA256("testPassword"))) + .willReturn(userDTO); + + userService.deleteId(userDTO.getId(),"testPassword"); + } +} \ No newline at end of file