feat: 更新端口配置并添加监控支持
fix: 修复测试配置和依赖检查 perf: 优化雪花算法性能 refactor: 清理冗余代码和未使用的导入 style: 统一代码格式和注释 test: 添加单元测试和集成测试 ci: 更新CI配置和构建脚本 chore: 更新依赖和配置文件
This commit is contained in:
+17
@@ -0,0 +1,17 @@
|
||||
package cn.novalon.manage.sys.config;
|
||||
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
@TestConfiguration
|
||||
public class UnitTestConfig {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public ConnectionFactory testConnectionFactory() {
|
||||
return Mockito.mock(ConnectionFactory.class);
|
||||
}
|
||||
}
|
||||
+183
-23
@@ -1,9 +1,11 @@
|
||||
package cn.novalon.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.manage.sys.core.domain.Dictionary;
|
||||
import cn.novalon.manage.sys.core.exception.DictionaryAlreadyExistsException;
|
||||
import cn.novalon.manage.sys.core.service.IDictionaryService;
|
||||
import cn.novalon.manage.sys.infrastructure.db.dao.DictionaryDao;
|
||||
import cn.novalon.manage.sys.infrastructure.db.converter.DictionaryConverter;
|
||||
import cn.novalon.manage.sys.infrastructure.db.entity.DictionaryEntity;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -13,9 +15,10 @@ import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class DictionaryServiceTest {
|
||||
@@ -28,55 +31,212 @@ class DictionaryServiceTest {
|
||||
|
||||
private IDictionaryService service;
|
||||
|
||||
private Dictionary testDictionary;
|
||||
private DictionaryEntity testEntity;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new DictionaryService(dao, converter);
|
||||
|
||||
testDictionary = new Dictionary();
|
||||
testDictionary.setId(1L);
|
||||
testDictionary.setType("test_type");
|
||||
testDictionary.setCode("test_code");
|
||||
testDictionary.setName("Test Label");
|
||||
testDictionary.setValue("test_value");
|
||||
testDictionary.setSort(1);
|
||||
testDictionary.setRemark("Test remark");
|
||||
testDictionary.setCreatedAt(LocalDateTime.now());
|
||||
testDictionary.setUpdatedAt(LocalDateTime.now());
|
||||
|
||||
testEntity = new DictionaryEntity();
|
||||
testEntity.setId(1L);
|
||||
testEntity.setType("test_type");
|
||||
testEntity.setCode("test_code");
|
||||
testEntity.setName("Test Label");
|
||||
testEntity.setValue("test_value");
|
||||
testEntity.setSort(1);
|
||||
testEntity.setRemark("Test remark");
|
||||
testEntity.setCreatedAt(LocalDateTime.now());
|
||||
testEntity.setUpdatedAt(LocalDateTime.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindAll() {
|
||||
Dictionary dict1 = new Dictionary();
|
||||
dict1.setId(1L);
|
||||
dict1.setType("type1");
|
||||
|
||||
Dictionary dict2 = new Dictionary();
|
||||
dict2.setId(2L);
|
||||
dict2.setType("type2");
|
||||
|
||||
when(dao.findByDeletedAtIsNullOrderBySortAsc()).thenReturn(Flux.empty());
|
||||
when(dao.findByDeletedAtIsNullOrderBySortAsc()).thenReturn(Flux.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testDictionary);
|
||||
|
||||
StepVerifier.create(service.findAll())
|
||||
.expectNext(testDictionary)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByDeletedAtIsNullOrderBySortAsc();
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindById() {
|
||||
Dictionary dict = new Dictionary();
|
||||
dict.setId(1L);
|
||||
dict.setType("type1");
|
||||
|
||||
when(dao.findById(1L)).thenReturn(Mono.empty());
|
||||
when(dao.findById(1L)).thenReturn(Mono.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testDictionary);
|
||||
|
||||
StepVerifier.create(service.findById(1L))
|
||||
.expectNext(testDictionary)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findById(1L);
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSave() {
|
||||
Dictionary dict = new Dictionary();
|
||||
dict.setId(1L);
|
||||
dict.setType("type1");
|
||||
void testFindById_NotFound() {
|
||||
when(dao.findById(999L)).thenReturn(Mono.empty());
|
||||
|
||||
when(dao.save(any())).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(service.save(dict))
|
||||
StepVerifier.create(service.findById(999L))
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findById(999L);
|
||||
verify(converter, never()).toDomain(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindByType() {
|
||||
when(dao.findByType("test_type")).thenReturn(Flux.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testDictionary);
|
||||
|
||||
StepVerifier.create(service.findByType("test_type"))
|
||||
.expectNext(testDictionary)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByType("test_type");
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckTypeAndCodeExists_True() {
|
||||
when(dao.findByTypeAndCode("test_type", "test_code")).thenReturn(Mono.just(testEntity));
|
||||
|
||||
StepVerifier.create(service.checkTypeAndCodeExists("test_type", "test_code"))
|
||||
.expectNext(true)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByTypeAndCode("test_type", "test_code");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckTypeAndCodeExists_False() {
|
||||
when(dao.findByTypeAndCode("test_type", "test_code")).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(service.checkTypeAndCodeExists("test_type", "test_code"))
|
||||
.expectNext(false)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByTypeAndCode("test_type", "test_code");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSave_NewDictionary_Success() {
|
||||
Dictionary newDict = new Dictionary();
|
||||
newDict.setType("test_type");
|
||||
newDict.setCode("test_code");
|
||||
newDict.setName("Test Label");
|
||||
newDict.setValue("test_value");
|
||||
|
||||
when(dao.findByTypeAndCode("test_type", "test_code")).thenReturn(Mono.empty());
|
||||
when(converter.toEntity(any())).thenReturn(testEntity);
|
||||
when(dao.save(any())).thenReturn(Mono.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testDictionary);
|
||||
|
||||
StepVerifier.create(service.save(newDict))
|
||||
.expectNextMatches(dict -> dict.getId() != null)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByTypeAndCode("test_type", "test_code");
|
||||
verify(converter).toEntity(any());
|
||||
verify(dao).save(any());
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSave_NewDictionary_AlreadyExists() {
|
||||
Dictionary newDict = new Dictionary();
|
||||
newDict.setType("test_type");
|
||||
newDict.setCode("test_code");
|
||||
|
||||
when(dao.findByTypeAndCode("test_type", "test_code")).thenReturn(Mono.just(testEntity));
|
||||
|
||||
StepVerifier.create(service.save(newDict))
|
||||
.expectError(DictionaryAlreadyExistsException.class)
|
||||
.verify();
|
||||
|
||||
verify(dao).findByTypeAndCode("test_type", "test_code");
|
||||
verify(converter, never()).toEntity(any());
|
||||
verify(dao, never()).save(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSave_UpdateExistingDictionary() {
|
||||
Dictionary existingDict = new Dictionary();
|
||||
existingDict.setId(1L);
|
||||
existingDict.setType("test_type");
|
||||
existingDict.setCode("test_code");
|
||||
|
||||
when(converter.toEntity(existingDict)).thenReturn(testEntity);
|
||||
when(dao.save(any())).thenReturn(Mono.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testDictionary);
|
||||
|
||||
StepVerifier.create(service.save(existingDict))
|
||||
.expectNextMatches(dict -> dict.getId() == 1L)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao, never()).findByTypeAndCode(anyString(), anyString());
|
||||
verify(converter).toEntity(existingDict);
|
||||
verify(dao).save(any());
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdate() {
|
||||
Dictionary updateDict = new Dictionary();
|
||||
updateDict.setName("Updated Name");
|
||||
updateDict.setValue("updated_value");
|
||||
updateDict.setRemark("Updated remark");
|
||||
updateDict.setSort(2);
|
||||
|
||||
DictionaryEntity existingEntity = new DictionaryEntity();
|
||||
existingEntity.setId(1L);
|
||||
existingEntity.setType("test_type");
|
||||
existingEntity.setCode("test_code");
|
||||
existingEntity.setName("Old Name");
|
||||
existingEntity.setValue("old_value");
|
||||
existingEntity.setRemark("Old remark");
|
||||
existingEntity.setSort(1);
|
||||
|
||||
when(dao.findById(1L)).thenReturn(Mono.just(existingEntity));
|
||||
when(dao.save(any())).thenReturn(Mono.just(existingEntity));
|
||||
when(converter.toDomain(existingEntity)).thenReturn(testDictionary);
|
||||
|
||||
StepVerifier.create(service.update(1L, updateDict))
|
||||
.expectNextMatches(dict -> dict.getId() == 1L)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findById(1L);
|
||||
verify(dao).save(any());
|
||||
verify(converter).toDomain(existingEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdate_NotFound() {
|
||||
Dictionary updateDict = new Dictionary();
|
||||
updateDict.setName("Updated Name");
|
||||
|
||||
when(dao.findById(999L)).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(service.update(999L, updateDict))
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findById(999L);
|
||||
verify(dao, never()).save(any());
|
||||
verify(converter, never()).toDomain(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
package cn.novalon.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.manage.sys.core.domain.SysConfig;
|
||||
import cn.novalon.manage.sys.infrastructure.db.converter.SysConfigConverter;
|
||||
import cn.novalon.manage.sys.infrastructure.db.dao.SysConfigDao;
|
||||
import cn.novalon.manage.sys.infrastructure.db.entity.SysConfigEntity;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class SysConfigServiceTest {
|
||||
|
||||
@Mock
|
||||
private SysConfigDao dao;
|
||||
|
||||
@Mock
|
||||
private SysConfigConverter converter;
|
||||
|
||||
private SysConfigService configService;
|
||||
|
||||
private SysConfig testConfig;
|
||||
private SysConfigEntity testEntity;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
configService = new SysConfigService(dao, converter);
|
||||
|
||||
testConfig = new SysConfig();
|
||||
testConfig.setId(1L);
|
||||
testConfig.setConfigKey("app.name");
|
||||
testConfig.setConfigValue("Novalon Manage System");
|
||||
testConfig.setConfigName("Application Name");
|
||||
testConfig.setConfigType("system");
|
||||
|
||||
testEntity = new SysConfigEntity();
|
||||
testEntity.setId(1L);
|
||||
testEntity.setConfigKey("app.name");
|
||||
testEntity.setConfigValue("Novalon Manage System");
|
||||
testEntity.setConfigName("Application Name");
|
||||
testEntity.setConfigType("system");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindAll() {
|
||||
when(dao.findByDeletedAtIsNull()).thenReturn(Flux.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testConfig);
|
||||
|
||||
StepVerifier.create(configService.findAll())
|
||||
.expectNext(testConfig)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByDeletedAtIsNull();
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindById() {
|
||||
when(dao.findById(1L)).thenReturn(Mono.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testConfig);
|
||||
|
||||
StepVerifier.create(configService.findById(1L))
|
||||
.expectNext(testConfig)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findById(1L);
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindById_NotFound() {
|
||||
when(dao.findById(999L)).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(configService.findById(999L))
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findById(999L);
|
||||
verify(converter, never()).toDomain(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindByConfigKey() {
|
||||
when(dao.findByConfigKeyAndDeletedAtIsNull("app.name")).thenReturn(Mono.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testConfig);
|
||||
|
||||
StepVerifier.create(configService.findByConfigKey("app.name"))
|
||||
.expectNext(testConfig)
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByConfigKeyAndDeletedAtIsNull("app.name");
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindByConfigKey_NotFound() {
|
||||
when(dao.findByConfigKeyAndDeletedAtIsNull("nonexistent")).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(configService.findByConfigKey("nonexistent"))
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByConfigKeyAndDeletedAtIsNull("nonexistent");
|
||||
verify(converter, never()).toDomain(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSave() {
|
||||
when(converter.toEntity(testConfig)).thenReturn(testEntity);
|
||||
when(dao.save(testEntity)).thenReturn(Mono.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testConfig);
|
||||
|
||||
StepVerifier.create(configService.save(testConfig))
|
||||
.expectNext(testConfig)
|
||||
.verifyComplete();
|
||||
|
||||
verify(converter).toEntity(testConfig);
|
||||
verify(dao).save(testEntity);
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteById() {
|
||||
when(dao.deleteByIdAndDeletedAtIsNull(1L)).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(configService.deleteById(1L))
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).deleteByIdAndDeletedAtIsNull(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetConfigValue() {
|
||||
when(dao.findByConfigKeyAndDeletedAtIsNull("app.name")).thenReturn(Mono.just(testEntity));
|
||||
when(converter.toDomain(testEntity)).thenReturn(testConfig);
|
||||
|
||||
StepVerifier.create(configService.getConfigValue("app.name"))
|
||||
.expectNext("Novalon Manage System")
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByConfigKeyAndDeletedAtIsNull("app.name");
|
||||
verify(converter).toDomain(testEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetConfigValue_NotFound() {
|
||||
when(dao.findByConfigKeyAndDeletedAtIsNull("nonexistent")).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(configService.getConfigValue("nonexistent"))
|
||||
.verifyComplete();
|
||||
|
||||
verify(dao).findByConfigKeyAndDeletedAtIsNull("nonexistent");
|
||||
}
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
package cn.novalon.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.manage.sys.core.constants.StatusConstants;
|
||||
import cn.novalon.manage.sys.core.domain.SysRole;
|
||||
import cn.novalon.manage.sys.core.repository.ISysRoleRepository;
|
||||
import cn.novalon.manage.sys.dto.request.PageRequest;
|
||||
import cn.novalon.manage.sys.dto.response.PageResponse;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.data.relational.core.query.Query;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class SysRoleServiceTest {
|
||||
|
||||
@Mock
|
||||
private ISysRoleRepository roleRepository;
|
||||
|
||||
private SysRoleService roleService;
|
||||
|
||||
private SysRole testRole;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
roleService = new SysRoleService(roleRepository);
|
||||
|
||||
testRole = new SysRole();
|
||||
testRole.setId(1L);
|
||||
testRole.setRoleName("admin");
|
||||
testRole.setRoleKey("admin");
|
||||
testRole.setStatus(StatusConstants.ENABLED);
|
||||
testRole.setCreatedAt(LocalDateTime.now());
|
||||
testRole.setUpdatedAt(LocalDateTime.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindById() {
|
||||
when(roleRepository.findById(1L)).thenReturn(Mono.just(testRole));
|
||||
|
||||
StepVerifier.create(roleService.findById(1L))
|
||||
.expectNext(testRole)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).findById(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindAll() {
|
||||
when(roleRepository.findAll()).thenReturn(Flux.just(testRole));
|
||||
|
||||
StepVerifier.create(roleService.findAll())
|
||||
.expectNext(testRole)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).findAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindRolesByPage() {
|
||||
PageRequest pageRequest = new PageRequest();
|
||||
pageRequest.setPage(0);
|
||||
pageRequest.setSize(10);
|
||||
pageRequest.setKeyword("admin");
|
||||
|
||||
PageResponse<SysRole> pageResponse = new PageResponse<>();
|
||||
pageResponse.setContent(List.of(testRole));
|
||||
pageResponse.setTotalElements(1L);
|
||||
|
||||
when(roleRepository.findByQueryWithPagination(any(Query.class), eq(pageRequest)))
|
||||
.thenReturn(Mono.just(pageResponse));
|
||||
|
||||
StepVerifier.create(roleService.findRolesByPage(pageRequest))
|
||||
.expectNextMatches(response -> response.getTotalElements() == 1L)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).findByQueryWithPagination(any(Query.class), eq(pageRequest));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCount() {
|
||||
when(roleRepository.count()).thenReturn(Mono.just(5L));
|
||||
|
||||
StepVerifier.create(roleService.count())
|
||||
.expectNext(5L)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).count();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateRole() {
|
||||
SysRole newRole = new SysRole();
|
||||
newRole.setRoleName("user");
|
||||
newRole.setRoleKey("user");
|
||||
|
||||
when(roleRepository.save(any(SysRole.class))).thenReturn(Mono.just(testRole));
|
||||
|
||||
StepVerifier.create(roleService.createRole(newRole))
|
||||
.expectNextMatches(role ->
|
||||
role.getStatus().equals(StatusConstants.ENABLED) &&
|
||||
role.getCreatedAt() != null)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).save(any(SysRole.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdateRole() {
|
||||
SysRole updateRole = new SysRole();
|
||||
updateRole.setId(1L);
|
||||
updateRole.setRoleName("updated_admin");
|
||||
|
||||
when(roleRepository.save(any(SysRole.class))).thenReturn(Mono.just(testRole));
|
||||
|
||||
StepVerifier.create(roleService.updateRole(updateRole))
|
||||
.expectNextMatches(role -> role.getUpdatedAt() != null)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).save(any(SysRole.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteRole() {
|
||||
when(roleRepository.deleteById(1L)).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(roleService.deleteRole(1L))
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).deleteById(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindByRoleName() {
|
||||
when(roleRepository.findByRoleName("admin")).thenReturn(Mono.just(testRole));
|
||||
|
||||
StepVerifier.create(roleService.findByRoleName("admin"))
|
||||
.expectNext(testRole)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).findByRoleName("admin");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExistsByRoleName_True() {
|
||||
when(roleRepository.existsByRoleName("admin")).thenReturn(Mono.just(true));
|
||||
|
||||
StepVerifier.create(roleService.existsByRoleName("admin"))
|
||||
.expectNext(true)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).existsByRoleName("admin");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExistsByRoleName_False() {
|
||||
when(roleRepository.existsByRoleName("nonexistent")).thenReturn(Mono.just(false));
|
||||
|
||||
StepVerifier.create(roleService.existsByRoleName("nonexistent"))
|
||||
.expectNext(false)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).existsByRoleName("nonexistent");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLogicalDeleteRole() {
|
||||
when(roleRepository.findByIdIncludingDeleted(1L)).thenReturn(Mono.just(testRole));
|
||||
when(roleRepository.updateRole(any(SysRole.class))).thenReturn(Mono.just(testRole));
|
||||
|
||||
StepVerifier.create(roleService.logicalDeleteRole(1L))
|
||||
.expectNextMatches(role -> role.getDeletedAt() != null)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).findByIdIncludingDeleted(1L);
|
||||
verify(roleRepository).updateRole(any(SysRole.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRestoreRole() {
|
||||
SysRole deletedRole = new SysRole();
|
||||
deletedRole.setId(1L);
|
||||
deletedRole.setDeletedAt(LocalDateTime.now());
|
||||
|
||||
when(roleRepository.findByIdIncludingDeleted(1L)).thenReturn(Mono.just(deletedRole));
|
||||
when(roleRepository.updateRole(any(SysRole.class))).thenReturn(Mono.just(testRole));
|
||||
|
||||
StepVerifier.create(roleService.restoreRole(1L))
|
||||
.expectNextMatches(role -> role.getDeletedAt() == null)
|
||||
.verifyComplete();
|
||||
|
||||
verify(roleRepository).findByIdIncludingDeleted(1L);
|
||||
verify(roleRepository).updateRole(any(SysRole.class));
|
||||
}
|
||||
}
|
||||
+334
@@ -0,0 +1,334 @@
|
||||
package cn.novalon.manage.sys.core.service.impl;
|
||||
|
||||
import cn.novalon.manage.sys.core.constants.StatusConstants;
|
||||
import cn.novalon.manage.sys.core.domain.SysUser;
|
||||
import cn.novalon.manage.sys.core.repository.ISysUserRepository;
|
||||
import cn.novalon.manage.sys.dto.request.PageRequest;
|
||||
import cn.novalon.manage.sys.dto.response.PageResponse;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.data.relational.core.query.Query;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class SysUserServiceTest {
|
||||
|
||||
@Mock
|
||||
private ISysUserRepository userRepository;
|
||||
|
||||
@Mock
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
private SysUserService userService;
|
||||
|
||||
private SysUser testUser;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
userService = new SysUserService(userRepository, passwordEncoder);
|
||||
|
||||
testUser = new SysUser();
|
||||
testUser.setId(1L);
|
||||
testUser.setUsername("testuser");
|
||||
testUser.setPassword("encoded_password");
|
||||
testUser.setEmail("test@example.com");
|
||||
testUser.setRoleId(1L);
|
||||
testUser.setStatus(StatusConstants.ENABLED);
|
||||
testUser.setCreatedAt(LocalDateTime.now());
|
||||
testUser.setUpdatedAt(LocalDateTime.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindById() {
|
||||
when(userRepository.findById(1L)).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.findById(1L))
|
||||
.expectNext(testUser)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findById(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindAll() {
|
||||
when(userRepository.findAll()).thenReturn(Flux.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.findAll())
|
||||
.expectNext(testUser)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindAll_IncludeDeleted() {
|
||||
when(userRepository.findAll()).thenReturn(Flux.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.findAll(true))
|
||||
.expectNext(testUser)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindAll_ExcludeDeleted() {
|
||||
when(userRepository.findByDeletedAtIsNull()).thenReturn(Flux.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.findAll(false))
|
||||
.expectNext(testUser)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findByDeletedAtIsNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindUsersByPage() {
|
||||
PageRequest pageRequest = new PageRequest();
|
||||
pageRequest.setPage(0);
|
||||
pageRequest.setSize(10);
|
||||
pageRequest.setKeyword("test");
|
||||
|
||||
PageResponse<SysUser> pageResponse = new PageResponse<>();
|
||||
pageResponse.setContent(List.of(testUser));
|
||||
pageResponse.setTotalElements(1L);
|
||||
|
||||
when(userRepository.findByQueryWithPagination(any(Query.class), eq(pageRequest)))
|
||||
.thenReturn(Mono.just(pageResponse));
|
||||
|
||||
StepVerifier.create(userService.findUsersByPage(pageRequest))
|
||||
.expectNextMatches(response -> response.getTotalElements() == 1L)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findByQueryWithPagination(any(Query.class), eq(pageRequest));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindUsersByPage_NoKeyword() {
|
||||
PageRequest pageRequest = new PageRequest();
|
||||
pageRequest.setPage(0);
|
||||
pageRequest.setSize(10);
|
||||
|
||||
PageResponse<SysUser> pageResponse = new PageResponse<>();
|
||||
pageResponse.setContent(List.of(testUser));
|
||||
pageResponse.setTotalElements(1L);
|
||||
|
||||
when(userRepository.findByQueryWithPagination(any(Query.class), eq(pageRequest)))
|
||||
.thenReturn(Mono.just(pageResponse));
|
||||
|
||||
StepVerifier.create(userService.findUsersByPage(pageRequest))
|
||||
.expectNextMatches(response -> response.getTotalElements() == 1L)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findByQueryWithPagination(any(Query.class), eq(pageRequest));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCount() {
|
||||
when(userRepository.count()).thenReturn(Mono.just(10L));
|
||||
|
||||
StepVerifier.create(userService.count())
|
||||
.expectNext(10L)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).count();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFindByUsername() {
|
||||
when(userRepository.findByUsername("testuser")).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.findByUsername("testuser"))
|
||||
.expectNext(testUser)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findByUsername("testuser");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateUser() {
|
||||
SysUser newUser = new SysUser();
|
||||
newUser.setUsername("newuser");
|
||||
newUser.setPassword("raw_password");
|
||||
newUser.setEmail("new@example.com");
|
||||
|
||||
when(passwordEncoder.encode("raw_password")).thenReturn("encoded_password");
|
||||
when(userRepository.save(any(SysUser.class))).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.createUser(newUser))
|
||||
.expectNextMatches(user ->
|
||||
user.getPassword().equals("encoded_password") &&
|
||||
user.getStatus().equals(StatusConstants.ENABLED) &&
|
||||
user.getCreatedAt() != null)
|
||||
.verifyComplete();
|
||||
|
||||
ArgumentCaptor<SysUser> userCaptor = ArgumentCaptor.forClass(SysUser.class);
|
||||
verify(userRepository).save(userCaptor.capture());
|
||||
verify(passwordEncoder).encode("raw_password");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdateUser() {
|
||||
SysUser updateUser = new SysUser();
|
||||
updateUser.setId(1L);
|
||||
updateUser.setUsername("updated_user");
|
||||
|
||||
when(userRepository.save(any(SysUser.class))).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.updateUser(updateUser))
|
||||
.expectNextMatches(user -> user.getUpdatedAt() != null)
|
||||
.verifyComplete();
|
||||
|
||||
ArgumentCaptor<SysUser> userCaptor = ArgumentCaptor.forClass(SysUser.class);
|
||||
verify(userRepository).save(userCaptor.capture());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteUser() {
|
||||
when(userRepository.deleteById(1L)).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(userService.deleteUser(1L))
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).deleteById(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChangePassword_Success() {
|
||||
when(userRepository.findById(1L)).thenReturn(Mono.just(testUser));
|
||||
when(passwordEncoder.matches("old_password", "encoded_password")).thenReturn(true);
|
||||
when(passwordEncoder.encode("new_password")).thenReturn("new_encoded_password");
|
||||
when(userRepository.save(any(SysUser.class))).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.changePassword(1L, "old_password", "new_password"))
|
||||
.expectNextMatches(user -> user.getPassword().equals("new_encoded_password"))
|
||||
.verifyComplete();
|
||||
|
||||
verify(passwordEncoder).matches("old_password", "encoded_password");
|
||||
verify(passwordEncoder).encode("new_password");
|
||||
verify(userRepository).save(any(SysUser.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testChangePassword_WrongOldPassword() {
|
||||
when(userRepository.findById(1L)).thenReturn(Mono.just(testUser));
|
||||
when(passwordEncoder.matches("wrong_password", "encoded_password")).thenReturn(false);
|
||||
|
||||
StepVerifier.create(userService.changePassword(1L, "wrong_password", "new_password"))
|
||||
.expectError(RuntimeException.class)
|
||||
.verify();
|
||||
|
||||
verify(passwordEncoder).matches("wrong_password", "encoded_password");
|
||||
verify(passwordEncoder, never()).encode(anyString());
|
||||
verify(userRepository, never()).save(any(SysUser.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExistsByUsername_True() {
|
||||
when(userRepository.findByUsername("testuser")).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.existsByUsername("testuser"))
|
||||
.expectNext(true)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findByUsername("testuser");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExistsByUsername_False() {
|
||||
when(userRepository.findByUsername("nonexistent")).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(userService.existsByUsername("nonexistent"))
|
||||
.expectNext(false)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findByUsername("nonexistent");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExistsByEmail_True() {
|
||||
when(userRepository.findByEmail("test@example.com")).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.existsByEmail("test@example.com"))
|
||||
.expectNext(true)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findByEmail("test@example.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExistsByEmail_False() {
|
||||
when(userRepository.findByEmail("nonexistent@example.com")).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(userService.existsByEmail("nonexistent@example.com"))
|
||||
.expectNext(false)
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).findByEmail("nonexistent@example.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLogicalDeleteUser() {
|
||||
when(userRepository.findByIdIncludingDeleted(1L)).thenReturn(Mono.just(testUser));
|
||||
when(userRepository.save(any(SysUser.class))).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.logicalDeleteUser(1L))
|
||||
.verifyComplete();
|
||||
|
||||
ArgumentCaptor<SysUser> userCaptor = ArgumentCaptor.forClass(SysUser.class);
|
||||
verify(userRepository).save(userCaptor.capture());
|
||||
assert userCaptor.getValue().getDeletedAt() != null : "DeletedAt should be set";
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLogicalDeleteUsers() {
|
||||
List<Long> ids = List.of(1L, 2L, 3L);
|
||||
when(userRepository.logicalDeleteByIds(ids)).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(userService.logicalDeleteUsers(ids))
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).logicalDeleteByIds(ids);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRestoreUser() {
|
||||
SysUser deletedUser = new SysUser();
|
||||
deletedUser.setId(1L);
|
||||
deletedUser.setDeletedAt(LocalDateTime.now());
|
||||
|
||||
when(userRepository.findByIdIncludingDeleted(1L)).thenReturn(Mono.just(deletedUser));
|
||||
when(userRepository.save(any(SysUser.class))).thenReturn(Mono.just(testUser));
|
||||
|
||||
StepVerifier.create(userService.restoreUser(1L))
|
||||
.verifyComplete();
|
||||
|
||||
ArgumentCaptor<SysUser> userCaptor = ArgumentCaptor.forClass(SysUser.class);
|
||||
verify(userRepository).save(userCaptor.capture());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRestoreUsers() {
|
||||
List<Long> ids = List.of(1L, 2L, 3L);
|
||||
when(userRepository.restoreByIds(ids)).thenReturn(Mono.empty());
|
||||
|
||||
StepVerifier.create(userService.restoreUsers(ids))
|
||||
.verifyComplete();
|
||||
|
||||
verify(userRepository).restoreByIds(ids);
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -77,8 +77,10 @@ class DictionaryHandlerTest {
|
||||
|
||||
when(service.save(any())).thenReturn(Mono.just(dict));
|
||||
|
||||
Mono<ServerResponse> responseMono = handler.createDictionary(MockServerRequest.builder()
|
||||
.build());
|
||||
MockServerRequest request = MockServerRequest.builder()
|
||||
.body(Mono.just(dict));
|
||||
|
||||
Mono<ServerResponse> responseMono = handler.createDictionary(request);
|
||||
|
||||
StepVerifier.create(responseMono)
|
||||
.expectNextMatches(response -> response.statusCode().equals(HttpStatus.CREATED))
|
||||
|
||||
+1
-2
@@ -4,7 +4,6 @@ import cn.novalon.manage.sys.core.domain.Dictionary;
|
||||
import cn.novalon.manage.sys.infrastructure.db.entity.DictionaryEntity;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -12,7 +11,7 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class DictionaryMapperTest {
|
||||
|
||||
private final DictionaryMapper mapper = DictionaryMapper.INSTANCE;
|
||||
private final DictionaryMapper mapper = Mappers.getMapper(DictionaryMapper.class);
|
||||
|
||||
@Test
|
||||
void testToDomain() {
|
||||
|
||||
-1
@@ -13,7 +13,6 @@ import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import http from 'k6/http';
|
||||
import { check, sleep } from 'k6';
|
||||
|
||||
export const options = {
|
||||
stages: [
|
||||
{ duration: '30s', target: 10 },
|
||||
{ duration: '1m', target: 50 },
|
||||
{ duration: '30s', target: 0 },
|
||||
],
|
||||
thresholds: {
|
||||
http_req_duration: ['p(95)<500'],
|
||||
http_req_failed: ['rate<0.01'],
|
||||
},
|
||||
};
|
||||
|
||||
const BASE_URL = __ENV.BASE_URL || 'http://localhost:8080';
|
||||
|
||||
export default function () {
|
||||
const responses = http.batch([
|
||||
['GET', `${BASE_URL}/api/users/page?page=0&size=10`, null, { tags: { name: 'UsersList' } }],
|
||||
['GET', `${BASE_URL}/api/roles/page?page=0&size=10`, null, { tags: { name: 'RolesList' } }],
|
||||
]);
|
||||
|
||||
check(responses[0], {
|
||||
'users status is 200': (r) => r.status === 200,
|
||||
'users response time < 500ms': (r) => r.timings.duration < 500,
|
||||
});
|
||||
|
||||
check(responses[1], {
|
||||
'roles status is 200': (r) => r.status === 200,
|
||||
'roles response time < 500ms': (r) => r.timings.duration < 500,
|
||||
});
|
||||
|
||||
const singleUserRes = http.get(`${BASE_URL}/api/users/1`);
|
||||
check(singleUserRes, {
|
||||
'single user status is 200 or 404': (r) => r.status === 200 || r.status === 404,
|
||||
'single user response time < 300ms': (r) => r.timings.duration < 300,
|
||||
});
|
||||
|
||||
const healthRes = http.get(`${BASE_URL}/actuator/health`);
|
||||
check(healthRes, {
|
||||
'health check status is 200': (r) => r.status === 200,
|
||||
'health check response time < 100ms': (r) => r.timings.duration < 100,
|
||||
});
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
export function handleSummary(data) {
|
||||
return {
|
||||
'stdout': textSummary(data, { indent: ' ', enableColors: true }),
|
||||
'performance-report.json': JSON.stringify(data, null, 2),
|
||||
};
|
||||
}
|
||||
|
||||
function textSummary(data, options) {
|
||||
const indent = options?.indent || '';
|
||||
const colors = options?.enableColors || false;
|
||||
|
||||
let summary = `\n${indent}📊 Performance Test Summary\n`;
|
||||
summary += `${indent}============================\n\n`;
|
||||
|
||||
summary += `${indent}⏱️ HTTP Metrics:\n`;
|
||||
summary += `${indent} - Total Requests: ${data.metrics.http_reqs?.values?.count || 0}\n`;
|
||||
summary += `${indent} - Request Duration (p95): ${data.metrics.http_req_duration?.values?.['p(95)']?.toFixed(2) || 0}ms\n`;
|
||||
summary += `${indent} - Request Failed Rate: ${(data.metrics.http_req_failed?.values?.rate * 100)?.toFixed(2) || 0}%\n`;
|
||||
|
||||
summary += `\n${indent}📈 Iterations:\n`;
|
||||
summary += `${indent} - Total: ${data.metrics.iterations?.values?.count || 0}\n`;
|
||||
summary += `${indent} - Rate: ${data.metrics.iterations?.values?.rate?.toFixed(2) || 0}/s\n`;
|
||||
|
||||
summary += `\n${indent}⏰ Test Duration: ${data.state?.testRunDurationMs ? (data.state.testRunDurationMs / 1000).toFixed(2) : 0}s\n`;
|
||||
|
||||
return summary;
|
||||
}
|
||||
Reference in New Issue
Block a user