feat: 增加简单的测试
This commit is contained in:
6
pom.xml
6
pom.xml
@@ -32,6 +32,12 @@
|
||||
<artifactId>fenix-spring-boot-starter</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
|
||||
@@ -6,7 +6,6 @@ import com.lanyuanxiaoyao.service.template.entity.SimpleEntity;
|
||||
import com.lanyuanxiaoyao.service.template.helper.ObjectHelper;
|
||||
import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport;
|
||||
import java.util.List;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -22,16 +21,17 @@ public abstract class SimpleControllerSupport<ENTITY extends SimpleEntity, SAVE_
|
||||
@PostMapping(SAVE)
|
||||
@Override
|
||||
public GlobalResponse<Long> save(@RequestBody SAVE_ITEM item) throws Exception {
|
||||
SaveItemMapper<ENTITY, SAVE_ITEM> mapper = saveItemMapper();
|
||||
var mapper = saveItemMapper();
|
||||
return GlobalResponse.responseSuccess(service.save(mapper.from(item)));
|
||||
}
|
||||
|
||||
@GetMapping(LIST)
|
||||
@Override
|
||||
public GlobalCrudResponse<LIST_ITEM> list() throws Exception {
|
||||
ListItemMapper<ENTITY, LIST_ITEM> mapper = listItemMapper();
|
||||
var mapper = listItemMapper();
|
||||
var result = service.list();
|
||||
return GlobalCrudResponse.responseCrudData(
|
||||
service.list()
|
||||
result
|
||||
.stream()
|
||||
.map(entity -> {
|
||||
try {
|
||||
@@ -40,7 +40,8 @@ public abstract class SimpleControllerSupport<ENTITY extends SimpleEntity, SAVE_
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
})
|
||||
.toList()
|
||||
.toList(),
|
||||
result.size()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -50,8 +51,8 @@ public abstract class SimpleControllerSupport<ENTITY extends SimpleEntity, SAVE_
|
||||
if (ObjectHelper.isNull(query)) {
|
||||
return GlobalCrudResponse.responseCrudData(List.of(), 0);
|
||||
}
|
||||
ListItemMapper<ENTITY, LIST_ITEM> mapper = listItemMapper();
|
||||
Page<ENTITY> result = service.list(query);
|
||||
var mapper = listItemMapper();
|
||||
var result = service.list(query);
|
||||
return GlobalCrudResponse.responseCrudData(
|
||||
result.get()
|
||||
.map(entity -> {
|
||||
@@ -69,7 +70,7 @@ public abstract class SimpleControllerSupport<ENTITY extends SimpleEntity, SAVE_
|
||||
@GetMapping(DETAIL)
|
||||
@Override
|
||||
public GlobalResponse<DETAIL_ITEM> detail(@PathVariable("id") Long id) throws Exception {
|
||||
DetailItemMapper<ENTITY, DETAIL_ITEM> mapper = detailItemMapper();
|
||||
var mapper = detailItemMapper();
|
||||
return GlobalResponse.responseSuccess(mapper.from(service.detailOrThrow(id)));
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,6 @@ public class SimpleEntity extends IdOnlyEntity {
|
||||
return "SimpleEntity{" +
|
||||
"createdTime=" + createdTime +
|
||||
", modifiedTime=" + modifiedTime +
|
||||
'}';
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,12 +14,15 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implements SimpleService<ENTITY> {
|
||||
private static final Logger log = LoggerFactory.getLogger(SimpleServiceSupport.class);
|
||||
private static final Integer DEFAULT_PAGE_INDEX = 1;
|
||||
private static final Integer DEFAULT_PAGE_SIZE = 10;
|
||||
protected final SimpleRepository<ENTITY, Long> repository;
|
||||
@@ -31,7 +34,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
||||
@Transactional(rollbackOn = Throwable.class)
|
||||
@Override
|
||||
public Long save(ENTITY entity) {
|
||||
if (!ObjectHelper.isNull(entity.getId())) {
|
||||
if (ObjectHelper.isNotNull(entity.getId())) {
|
||||
var id = entity.getId();
|
||||
var targetEntity = repository.findById(entity.getId()).orElseThrow(() -> new IdNotFoundException(id));
|
||||
BeanUtils.copyProperties(entity, targetEntity, "id", "created_time", "modified_time");
|
||||
@@ -82,7 +85,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
||||
if (ObjectHelper.isEmpty(column)) {
|
||||
throw new IllegalArgumentException("Column cannot be blank");
|
||||
}
|
||||
String[] columns = column.split("/");
|
||||
var columns = column.split("/");
|
||||
Path<Y> path = root.get(columns[0]);
|
||||
for (int i = 1; i < columns.length; i++) {
|
||||
path = path.get(columns[i]);
|
||||
@@ -92,15 +95,20 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private <Y> Object value(Path<Y> column, Object value) {
|
||||
Class<?> javaType = column.getJavaType();
|
||||
var javaType = column.getJavaType();
|
||||
if (javaType.isEnum()) {
|
||||
return Enum.valueOf((Class<Enum>) javaType, (String) value);
|
||||
if (value instanceof String enumName) {
|
||||
var enumType = (Class<Enum>) javaType;
|
||||
return Enum.valueOf(enumType, enumName);
|
||||
} else {
|
||||
throw new IllegalArgumentException("枚举类型字段需要String类型的值");
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
protected List<Predicate> queryPredicates(Query.Queryable queryable, Root<ENTITY> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
|
||||
List<Predicate> predicates = new ArrayList<>();
|
||||
var predicates = new ArrayList<Predicate>();
|
||||
if (ObjectHelper.isNull(queryable)) {
|
||||
return predicates;
|
||||
}
|
||||
@@ -118,13 +126,13 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.getEqual())) {
|
||||
queryable.getEqual().forEach((column, value) -> {
|
||||
Path<Object> path = column(root, column);
|
||||
var path = column(root, column);
|
||||
predicates.add(builder.equal(path, value(path, value)));
|
||||
});
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.getNotEqual())) {
|
||||
queryable.getEqual().forEach((column, value) -> {
|
||||
Path<Object> path = column(root, column);
|
||||
var path = column(root, column);
|
||||
predicates.add(builder.notEqual(path, value(path, value)));
|
||||
});
|
||||
}
|
||||
@@ -167,7 +175,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
||||
|
||||
@Override
|
||||
public Page<ENTITY> list(Query listQuery) {
|
||||
PageRequest pageRequest = PageRequest.of(DEFAULT_PAGE_INDEX - 1, DEFAULT_PAGE_SIZE, Sort.by("created_time").descending());
|
||||
var pageRequest = PageRequest.of(DEFAULT_PAGE_INDEX - 1, DEFAULT_PAGE_SIZE, Sort.by("created_time").descending());
|
||||
if (ObjectHelper.isNotNull(listQuery.getPage())) {
|
||||
pageRequest = PageRequest.of(
|
||||
ObjectHelper.defaultIfNull(listQuery.getPage().getIndex(), DEFAULT_PAGE_INDEX) - 1,
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
package com.lanyuanxiaoyao.service.template;
|
||||
|
||||
import com.blinkfox.fenix.EnableFenix;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* @author lanyuanxiaoyao
|
||||
* @version 20250814
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableFenix
|
||||
@EnableJpaAuditing
|
||||
public class TestApplication {
|
||||
private static final Logger log = LoggerFactory.getLogger(TestApplication.class);
|
||||
private static final String BASE_URL = "http://localhost:2490";
|
||||
private static final RestTemplate REST_CLIENT = new RestTemplate();
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(TestApplication.class, args);
|
||||
}
|
||||
|
||||
@EventListener(ApplicationReadyEvent.class)
|
||||
public void runTests() throws JsonProcessingException {
|
||||
// 增
|
||||
var cid1 = saveItem("company", "{\"name\": \"Apple\"}").get("data").asLong();
|
||||
var cid2 = saveItem("company", "{\"name\": \"Banana\"}").get("data").asLong();
|
||||
var cid3 = saveItem("company", "{\"name\": \"Cheery\"}").get("data").asLong();
|
||||
|
||||
// 查
|
||||
var companies = listItems("company");
|
||||
Assert.isTrue(companies.at("/data/items").size() == 3, "数量错误");
|
||||
Assert.isTrue(companies.at("/data/total").asLong() == 3, "返回数量错误");
|
||||
|
||||
var company1 = detailItem("company", cid1);
|
||||
Assert.isTrue(cid1 == company1.at("/data/id").asLong(), "id错误");
|
||||
Assert.isTrue("Apple".equals(company1.at("/data/name").asText()), "name错误");
|
||||
|
||||
// 改
|
||||
var cid4 = saveItem("company", "{\"id\": %d, \"name\": \"Dog\"}".formatted(cid2)).get("data").asLong();
|
||||
Assert.isTrue(cid2 == cid4, "id错误");
|
||||
var company2 = detailItem("company", cid2);
|
||||
Assert.isTrue("Dog".equals(company2.at("/data/name").asText()), "name错误");
|
||||
|
||||
// 删
|
||||
removeItem("company", cid3);
|
||||
Assert.isTrue(listItems("company").at("/data/items").size() == 2, "数量错误");
|
||||
Assert.isTrue(listItems("company").at("/data/total").asLong() == 2, "返回数量错误");
|
||||
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
private HttpHeaders headers() {
|
||||
var headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
return headers;
|
||||
}
|
||||
|
||||
private JsonNode saveItem(String path, String body) throws JsonProcessingException {
|
||||
var response = REST_CLIENT.postForEntity(
|
||||
"%s/%s/save".formatted(BASE_URL, path),
|
||||
new HttpEntity<>(body, headers()),
|
||||
String.class
|
||||
);
|
||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
||||
Assert.notNull(response.getBody(), "请求失败");
|
||||
return MAPPER.readTree(response.getBody());
|
||||
}
|
||||
|
||||
private JsonNode listItems(String path) throws JsonProcessingException {
|
||||
var response = REST_CLIENT.getForEntity(
|
||||
"%s/%s/list".formatted(BASE_URL, path),
|
||||
String.class
|
||||
);
|
||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
||||
Assert.notNull(response.getBody(), "请求失败");
|
||||
return MAPPER.readTree(response.getBody());
|
||||
}
|
||||
|
||||
private JsonNode detailItem(String path, Long id) throws JsonProcessingException {
|
||||
var response = REST_CLIENT.getForEntity(
|
||||
"%s/%s/detail/%d".formatted(BASE_URL, path, id),
|
||||
String.class
|
||||
);
|
||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
||||
Assert.notNull(response.getBody(), "请求失败");
|
||||
return MAPPER.readTree(response.getBody());
|
||||
}
|
||||
|
||||
private void removeItem(String path, Long id) {
|
||||
var response = REST_CLIENT.getForEntity(
|
||||
"%s/%s/remove/%d".formatted(BASE_URL, path, id),
|
||||
Void.class
|
||||
);
|
||||
Assert.isTrue(response.getStatusCode().is2xxSuccessful(), "请求失败");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package com.lanyuanxiaoyao.service.template.controller;
|
||||
|
||||
import com.lanyuanxiaoyao.service.template.entity.Company;
|
||||
import com.lanyuanxiaoyao.service.template.service.CompanyService;
|
||||
import java.time.LocalDateTime;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author lanyuanxiaoyao
|
||||
* @version 20250814
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("company")
|
||||
public class CompanyController extends SimpleControllerSupport<Company, CompanyController.SaveItem, CompanyController.ListItem, CompanyController.DetailItem> {
|
||||
public CompanyController(CompanyService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SaveItemMapper<Company, SaveItem> saveItemMapper() {
|
||||
return item -> {
|
||||
var company = new Company();
|
||||
company.setId(item.getId());
|
||||
company.setName(item.getName());
|
||||
return company;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListItemMapper<Company, ListItem> listItemMapper() {
|
||||
return company -> {
|
||||
var item = new ListItem();
|
||||
item.setId(company.getId());
|
||||
item.setName(company.getName());
|
||||
return item;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DetailItemMapper<Company, DetailItem> detailItemMapper() {
|
||||
return company -> {
|
||||
var item = new DetailItem();
|
||||
item.setId(company.getId());
|
||||
item.setName(company.getName());
|
||||
item.setCreatedTime(company.getCreatedTime());
|
||||
item.setModifiedTime(company.getModifiedTime());
|
||||
return item;
|
||||
};
|
||||
}
|
||||
|
||||
public static class SaveItem {
|
||||
private Long id;
|
||||
private String name;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SaveItem{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static class ListItem {
|
||||
private Long id;
|
||||
private String name;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ListItem{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static class DetailItem {
|
||||
private Long id;
|
||||
private String name;
|
||||
private LocalDateTime createdTime;
|
||||
private LocalDateTime modifiedTime;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedTime() {
|
||||
return createdTime;
|
||||
}
|
||||
|
||||
public void setCreatedTime(LocalDateTime createdTime) {
|
||||
this.createdTime = createdTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getModifiedTime() {
|
||||
return modifiedTime;
|
||||
}
|
||||
|
||||
public void setModifiedTime(LocalDateTime modifiedTime) {
|
||||
this.modifiedTime = modifiedTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DetailItem{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
", createdTime=" + createdTime +
|
||||
", modifiedTime=" + modifiedTime +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.lanyuanxiaoyao.service.template.entity;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import org.hibernate.annotations.Comment;
|
||||
import org.hibernate.annotations.DynamicUpdate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
|
||||
@Entity
|
||||
@DynamicUpdate
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
@Comment("企业")
|
||||
public class Company extends SimpleEntity {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Company{" +
|
||||
"name='" + name + '\'' +
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.lanyuanxiaoyao.service.template.repository;
|
||||
|
||||
import com.lanyuanxiaoyao.service.template.entity.Company;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* @author lanyuanxiaoyao
|
||||
* @version 20250814
|
||||
*/
|
||||
@Repository
|
||||
public interface CompanyRepository extends SimpleRepository<Company, Long> {
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.lanyuanxiaoyao.service.template.service;
|
||||
|
||||
import com.lanyuanxiaoyao.service.template.entity.Company;
|
||||
import com.lanyuanxiaoyao.service.template.repository.CompanyRepository;
|
||||
import com.lanyuanxiaoyao.service.template.repository.SimpleRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author lanyuanxiaoyao
|
||||
* @version 20250814
|
||||
*/
|
||||
@Service
|
||||
public class CompanyService extends SimpleServiceSupport<Company> {
|
||||
public CompanyService(CompanyRepository repository) {
|
||||
super(repository);
|
||||
}
|
||||
}
|
||||
15
src/test/resources/application.yml
Normal file
15
src/test/resources/application.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
server:
|
||||
port: 2490
|
||||
spring:
|
||||
application:
|
||||
name: Test
|
||||
datasource:
|
||||
url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
|
||||
username: test
|
||||
password: test
|
||||
driver-class-name: org.h2.Driver
|
||||
jpa:
|
||||
show-sql: true
|
||||
generate-ddl: true
|
||||
fenix:
|
||||
print-banner: false
|
||||
Reference in New Issue
Block a user