ai-engineering-init 1.3.3 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/.claude/hooks/skill-forced-eval.js +4 -1
  2. package/.claude/settings.json +3 -3
  3. package/.claude/skills/add-skill/SKILL.md +252 -116
  4. package/.claude/skills/api-development/SKILL.md +83 -377
  5. package/.claude/skills/architecture-design/SKILL.md +138 -632
  6. package/.claude/skills/backend-annotations/SKILL.md +134 -506
  7. package/.claude/skills/banana-image/SKILL.md +10 -3
  8. package/.claude/skills/brainstorm/SKILL.md +103 -535
  9. package/.claude/skills/bug-detective/SKILL.md +147 -1097
  10. package/.claude/skills/bug-detective/references/error-patterns.md +242 -0
  11. package/.claude/skills/code-patterns/SKILL.md +116 -426
  12. package/.claude/skills/code-patterns/references/leniu-code-patterns.md +87 -0
  13. package/.claude/skills/crud-development/SKILL.md +64 -304
  14. package/.claude/skills/data-permission/SKILL.md +105 -412
  15. package/.claude/skills/data-permission/references/custom-data-scope.md +90 -0
  16. package/.claude/skills/file-oss-management/SKILL.md +106 -714
  17. package/.claude/skills/file-oss-management/references/entities.md +105 -0
  18. package/.claude/skills/file-oss-management/references/service-impl.md +104 -0
  19. package/.claude/skills/leniu-api-development/SKILL.md +142 -626
  20. package/.claude/skills/leniu-api-development/references/real-examples.md +273 -0
  21. package/.claude/skills/leniu-architecture-design/SKILL.md +176 -391
  22. package/.claude/skills/leniu-backend-annotations/SKILL.md +132 -519
  23. package/.claude/skills/leniu-brainstorm/SKILL.md +132 -541
  24. package/.claude/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
  25. package/.claude/skills/leniu-crud-development/SKILL.md +232 -938
  26. package/.claude/skills/leniu-crud-development/references/templates.md +597 -0
  27. package/.claude/skills/leniu-customization-location/SKILL.md +410 -0
  28. package/.claude/skills/leniu-data-permission/SKILL.md +70 -0
  29. package/.claude/skills/leniu-java-entity/SKILL.md +76 -590
  30. package/.claude/skills/leniu-java-entity/references/templates.md +237 -0
  31. package/.claude/skills/leniu-java-export/SKILL.md +94 -379
  32. package/.claude/skills/leniu-java-logging/SKILL.md +106 -709
  33. package/.claude/skills/leniu-java-logging/references/data-mask.md +46 -0
  34. package/.claude/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
  35. package/.claude/skills/leniu-java-mybatis/SKILL.md +73 -446
  36. package/.claude/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
  37. package/.claude/skills/leniu-report-customization/SKILL.md +111 -325
  38. package/.claude/skills/leniu-report-customization/references/table-fields.md +93 -0
  39. package/.claude/skills/leniu-report-standard-customization/SKILL.md +328 -0
  40. package/.claude/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
  41. package/.claude/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
  42. package/.claude/skills/leniu-security-guard/SKILL.md +133 -347
  43. package/.claude/skills/mysql-debug/SKILL.md +364 -0
  44. package/.claude/skills/openspec-apply-change/SKILL.md +10 -1
  45. package/.claude/skills/openspec-archive-change/SKILL.md +9 -1
  46. package/.claude/skills/openspec-bulk-archive-change/SKILL.md +9 -1
  47. package/.claude/skills/openspec-continue-change/SKILL.md +9 -1
  48. package/.claude/skills/openspec-explore/SKILL.md +10 -1
  49. package/.claude/skills/openspec-ff-change/SKILL.md +9 -1
  50. package/.claude/skills/openspec-new-change/SKILL.md +9 -1
  51. package/.claude/skills/openspec-onboard/SKILL.md +15 -130
  52. package/.claude/skills/openspec-sync-specs/SKILL.md +9 -1
  53. package/.claude/skills/openspec-verify-change/SKILL.md +9 -1
  54. package/.claude/skills/performance-doctor/SKILL.md +110 -434
  55. package/.claude/skills/redis-cache/SKILL.md +89 -595
  56. package/.claude/skills/redis-cache/references/listeners.md +23 -0
  57. package/.claude/skills/scheduled-jobs/SKILL.md +88 -407
  58. package/.claude/skills/security-guard/SKILL.md +137 -532
  59. package/.claude/skills/security-guard/references/encrypt-config.md +103 -0
  60. package/.claude/skills/security-guard/references/sensitive-strategies.md +42 -0
  61. package/.claude/skills/sms-mail/SKILL.md +116 -574
  62. package/.claude/skills/sms-mail/references/mail-config.md +88 -0
  63. package/.claude/skills/sms-mail/references/sms-config.md +74 -0
  64. package/.claude/skills/social-login/SKILL.md +112 -514
  65. package/.claude/skills/social-login/references/provider-configs.md +118 -0
  66. package/.claude/skills/tenant-management/SKILL.md +129 -444
  67. package/.claude/skills/tenant-management/references/tenant-scenarios.md +91 -0
  68. package/.claude/skills/test-development/SKILL.md +86 -540
  69. package/.claude/skills/test-development/references/parameterized-examples.md +119 -0
  70. package/.claude/skills/utils-toolkit/SKILL.md +52 -305
  71. package/.claude/skills/utils-toolkit/references/redis-utils-api.md +56 -0
  72. package/.claude/skills/websocket-sse/SKILL.md +105 -550
  73. package/.claude/skills/workflow-engine/SKILL.md +147 -502
  74. package/.codex/skills/add-skill/SKILL.md +252 -116
  75. package/.codex/skills/api-development/SKILL.md +172 -599
  76. package/.codex/skills/architecture-design/SKILL.md +138 -504
  77. package/.codex/skills/backend-annotations/SKILL.md +134 -496
  78. package/.codex/skills/banana-image/SKILL.md +10 -3
  79. package/.codex/skills/brainstorm/SKILL.md +103 -535
  80. package/.codex/skills/bug-detective/SKILL.md +147 -1097
  81. package/.codex/skills/bug-detective/references/error-patterns.md +242 -0
  82. package/.codex/skills/code-patterns/SKILL.md +120 -282
  83. package/.codex/skills/code-patterns/references/leniu-code-patterns.md +87 -0
  84. package/.codex/skills/crud-development/SKILL.md +64 -292
  85. package/.codex/skills/data-permission/SKILL.md +108 -407
  86. package/.codex/skills/data-permission/references/custom-data-scope.md +90 -0
  87. package/.codex/skills/database-ops/SKILL.md +8 -154
  88. package/.codex/skills/error-handler/SKILL.md +10 -0
  89. package/.codex/skills/file-oss-management/SKILL.md +106 -714
  90. package/.codex/skills/file-oss-management/references/entities.md +105 -0
  91. package/.codex/skills/file-oss-management/references/service-impl.md +104 -0
  92. package/.codex/skills/git-workflow/SKILL.md +27 -5
  93. package/.codex/skills/leniu-api-development/SKILL.md +142 -626
  94. package/.codex/skills/leniu-api-development/references/real-examples.md +273 -0
  95. package/.codex/skills/leniu-architecture-design/SKILL.md +176 -391
  96. package/.codex/skills/leniu-backend-annotations/SKILL.md +132 -519
  97. package/.codex/skills/leniu-brainstorm/SKILL.md +132 -541
  98. package/.codex/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
  99. package/.codex/skills/leniu-crud-development/SKILL.md +232 -938
  100. package/.codex/skills/leniu-crud-development/references/templates.md +597 -0
  101. package/.codex/skills/leniu-customization-location/SKILL.md +410 -0
  102. package/.codex/skills/leniu-data-permission/SKILL.md +70 -0
  103. package/.codex/skills/leniu-java-code-style/SKILL.md +510 -0
  104. package/.codex/skills/leniu-java-entity/SKILL.md +76 -590
  105. package/.codex/skills/leniu-java-entity/references/templates.md +237 -0
  106. package/.codex/skills/leniu-java-export/SKILL.md +94 -379
  107. package/.codex/skills/leniu-java-logging/SKILL.md +106 -709
  108. package/.codex/skills/leniu-java-logging/references/data-mask.md +46 -0
  109. package/.codex/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
  110. package/.codex/skills/leniu-java-mybatis/SKILL.md +73 -446
  111. package/.codex/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
  112. package/.codex/skills/leniu-report-customization/SKILL.md +111 -325
  113. package/.codex/skills/leniu-report-customization/references/table-fields.md +93 -0
  114. package/.codex/skills/leniu-report-standard-customization/SKILL.md +328 -0
  115. package/.codex/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
  116. package/.codex/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
  117. package/.codex/skills/leniu-security-guard/SKILL.md +133 -347
  118. package/.codex/skills/mysql-debug/SKILL.md +364 -0
  119. package/.codex/skills/openspec-apply-change/SKILL.md +10 -1
  120. package/.codex/skills/openspec-archive-change/SKILL.md +9 -1
  121. package/.codex/skills/openspec-bulk-archive-change/SKILL.md +9 -1
  122. package/.codex/skills/openspec-continue-change/SKILL.md +9 -1
  123. package/.codex/skills/openspec-explore/SKILL.md +10 -1
  124. package/.codex/skills/openspec-ff-change/SKILL.md +9 -1
  125. package/.codex/skills/openspec-new-change/SKILL.md +9 -1
  126. package/.codex/skills/openspec-onboard/SKILL.md +15 -130
  127. package/.codex/skills/openspec-sync-specs/SKILL.md +9 -1
  128. package/.codex/skills/openspec-verify-change/SKILL.md +9 -1
  129. package/.codex/skills/performance-doctor/SKILL.md +110 -434
  130. package/.codex/skills/project-navigator/SKILL.md +20 -1
  131. package/.codex/skills/redis-cache/SKILL.md +93 -589
  132. package/.codex/skills/redis-cache/references/listeners.md +23 -0
  133. package/.codex/skills/scheduled-jobs/SKILL.md +88 -407
  134. package/.codex/skills/security-guard/SKILL.md +141 -527
  135. package/.codex/skills/security-guard/references/encrypt-config.md +103 -0
  136. package/.codex/skills/security-guard/references/sensitive-strategies.md +42 -0
  137. package/.codex/skills/sms-mail/SKILL.md +116 -574
  138. package/.codex/skills/sms-mail/references/mail-config.md +88 -0
  139. package/.codex/skills/sms-mail/references/sms-config.md +74 -0
  140. package/.codex/skills/social-login/SKILL.md +112 -514
  141. package/.codex/skills/social-login/references/provider-configs.md +118 -0
  142. package/.codex/skills/store-pc/SKILL.md +258 -383
  143. package/.codex/skills/tenant-management/SKILL.md +129 -444
  144. package/.codex/skills/tenant-management/references/tenant-scenarios.md +91 -0
  145. package/.codex/skills/test-development/SKILL.md +86 -540
  146. package/.codex/skills/test-development/references/parameterized-examples.md +119 -0
  147. package/.codex/skills/ui-pc/SKILL.md +350 -387
  148. package/.codex/skills/utils-toolkit/SKILL.md +52 -283
  149. package/.codex/skills/utils-toolkit/references/redis-utils-api.md +56 -0
  150. package/.codex/skills/websocket-sse/SKILL.md +105 -550
  151. package/.codex/skills/workflow-engine/SKILL.md +147 -502
  152. package/.cursor/hooks.json +3 -3
  153. package/.cursor/rules/skill-activation.mdc +2 -0
  154. package/.cursor/skills/add-skill/SKILL.md +252 -116
  155. package/.cursor/skills/api-development/SKILL.md +83 -377
  156. package/.cursor/skills/architecture-design/SKILL.md +138 -632
  157. package/.cursor/skills/backend-annotations/SKILL.md +134 -506
  158. package/.cursor/skills/banana-image/SKILL.md +10 -3
  159. package/.cursor/skills/brainstorm/SKILL.md +103 -535
  160. package/.cursor/skills/bug-detective/SKILL.md +147 -1097
  161. package/.cursor/skills/bug-detective/references/error-patterns.md +242 -0
  162. package/.cursor/skills/code-patterns/SKILL.md +116 -426
  163. package/.cursor/skills/code-patterns/references/leniu-code-patterns.md +87 -0
  164. package/.cursor/skills/crud-development/SKILL.md +64 -304
  165. package/.cursor/skills/data-permission/SKILL.md +105 -412
  166. package/.cursor/skills/data-permission/references/custom-data-scope.md +90 -0
  167. package/.cursor/skills/file-oss-management/SKILL.md +106 -714
  168. package/.cursor/skills/file-oss-management/references/entities.md +105 -0
  169. package/.cursor/skills/file-oss-management/references/service-impl.md +104 -0
  170. package/.cursor/skills/git-workflow/SKILL.md +27 -5
  171. package/.cursor/skills/leniu-api-development/SKILL.md +142 -626
  172. package/.cursor/skills/leniu-api-development/references/real-examples.md +273 -0
  173. package/.cursor/skills/leniu-architecture-design/SKILL.md +176 -391
  174. package/.cursor/skills/leniu-backend-annotations/SKILL.md +132 -519
  175. package/.cursor/skills/leniu-brainstorm/SKILL.md +132 -541
  176. package/.cursor/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
  177. package/.cursor/skills/leniu-crud-development/SKILL.md +232 -938
  178. package/.cursor/skills/leniu-crud-development/references/templates.md +597 -0
  179. package/.cursor/skills/leniu-customization-location/SKILL.md +410 -0
  180. package/.cursor/skills/leniu-data-permission/SKILL.md +70 -0
  181. package/.cursor/skills/leniu-java-code-style/SKILL.md +510 -0
  182. package/.cursor/skills/leniu-java-entity/SKILL.md +76 -590
  183. package/.cursor/skills/leniu-java-entity/references/templates.md +237 -0
  184. package/.cursor/skills/leniu-java-export/SKILL.md +94 -379
  185. package/.cursor/skills/leniu-java-logging/SKILL.md +106 -709
  186. package/.cursor/skills/leniu-java-logging/references/data-mask.md +46 -0
  187. package/.cursor/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
  188. package/.cursor/skills/leniu-java-mybatis/SKILL.md +73 -446
  189. package/.cursor/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
  190. package/.cursor/skills/leniu-report-customization/SKILL.md +111 -325
  191. package/.cursor/skills/leniu-report-customization/references/table-fields.md +93 -0
  192. package/.cursor/skills/leniu-report-standard-customization/SKILL.md +328 -0
  193. package/.cursor/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
  194. package/.cursor/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
  195. package/.cursor/skills/leniu-security-guard/SKILL.md +133 -347
  196. package/.cursor/skills/mysql-debug/SKILL.md +364 -0
  197. package/.cursor/skills/openspec-apply-change/SKILL.md +10 -1
  198. package/.cursor/skills/openspec-archive-change/SKILL.md +9 -1
  199. package/.cursor/skills/openspec-bulk-archive-change/SKILL.md +9 -1
  200. package/.cursor/skills/openspec-continue-change/SKILL.md +9 -1
  201. package/.cursor/skills/openspec-explore/SKILL.md +10 -1
  202. package/.cursor/skills/openspec-ff-change/SKILL.md +9 -1
  203. package/.cursor/skills/openspec-new-change/SKILL.md +9 -1
  204. package/.cursor/skills/openspec-onboard/SKILL.md +15 -130
  205. package/.cursor/skills/openspec-sync-specs/SKILL.md +9 -1
  206. package/.cursor/skills/openspec-verify-change/SKILL.md +9 -1
  207. package/.cursor/skills/performance-doctor/SKILL.md +110 -434
  208. package/.cursor/skills/redis-cache/SKILL.md +89 -595
  209. package/.cursor/skills/redis-cache/references/listeners.md +23 -0
  210. package/.cursor/skills/scheduled-jobs/SKILL.md +88 -407
  211. package/.cursor/skills/security-guard/SKILL.md +137 -532
  212. package/.cursor/skills/security-guard/references/encrypt-config.md +103 -0
  213. package/.cursor/skills/security-guard/references/sensitive-strategies.md +42 -0
  214. package/.cursor/skills/sms-mail/SKILL.md +116 -574
  215. package/.cursor/skills/sms-mail/references/mail-config.md +88 -0
  216. package/.cursor/skills/sms-mail/references/sms-config.md +74 -0
  217. package/.cursor/skills/social-login/SKILL.md +112 -514
  218. package/.cursor/skills/social-login/references/provider-configs.md +118 -0
  219. package/.cursor/skills/tenant-management/SKILL.md +129 -444
  220. package/.cursor/skills/tenant-management/references/tenant-scenarios.md +91 -0
  221. package/.cursor/skills/test-development/SKILL.md +86 -540
  222. package/.cursor/skills/test-development/references/parameterized-examples.md +119 -0
  223. package/.cursor/skills/utils-toolkit/SKILL.md +52 -305
  224. package/.cursor/skills/utils-toolkit/references/redis-utils-api.md +56 -0
  225. package/.cursor/skills/websocket-sse/SKILL.md +105 -550
  226. package/.cursor/skills/workflow-engine/SKILL.md +147 -502
  227. package/AGENTS.md +1 -0
  228. package/package.json +1 -1
@@ -18,45 +18,25 @@ description: |
18
18
 
19
19
  # 测试开发规范
20
20
 
21
- > **核心原则**:本项目使用标准的 JUnit5 + Spring Boot Test,根据测试场景选择是否启动 Spring 容器!
22
-
23
21
  ## 测试分层策略
24
22
 
25
- | 层次 | 测试类型 | 是否启动 Spring | 特点 | 执行速度 |
26
- |------|---------|----------------|------|---------|
27
- | **单元测试** | 工具类/枚举/POJO | 否 | 纯 JUnit5,无依赖注入 | < 1s |
28
- | **集成测试** | Service/Controller/Mapper | ✅ 是 | 使用 `@SpringBootTest`,完整 Spring 容器 | 5-10s |
23
+ | 层次 | 测试类型 | 启动 Spring | 执行速度 |
24
+ |------|---------|------------|---------|
25
+ | 单元测试 | 工具类/枚举/POJO | 否 | < 1s |
26
+ | 集成测试 | Service/Controller/Mapper | 是(`@SpringBootTest`) | 5-10s |
29
27
 
30
28
  ## 测试文件位置
31
29
 
32
- | 类型 | 位置 | 示例 |
33
- |------|------|------|
34
- | 测试类 | `src/test/java` | `ruoyi-admin/src/test/java/org/dromara/test/` |
35
- | 测试资源 | `src/test/resources` | 测试配置文件、测试数据等 |
36
-
37
- ## 核心依赖
38
-
39
- Spring Boot Test 已包含在 `spring-boot-starter-test` 中,包含:
40
- - **JUnit 5**:测试框架
41
- - **Mockito**:Mock 框架
42
- - **Spring Test**:Spring 测试支持
43
-
44
- ```xml
45
- <!-- 在业务模块的 pom.xml 中已包含 -->
46
- <dependency>
47
- <groupId>org.springframework.boot</groupId>
48
- <artifactId>spring-boot-starter-test</artifactId>
49
- <scope>test</scope>
50
- </dependency>
30
+ ```
31
+ src/test/java/org/dromara/test/ # 通用测试
32
+ src/test/java/org/dromara/{模块}/ # 模块测试(与源码包路径一致)
51
33
  ```
52
34
 
53
- ---
54
-
55
- ## 1. 单元测试(纯 JUnit5)
35
+ **重要**:`@SpringBootTest` 只能在 SpringBoot 主包下使用(需包含 main 方法和 yml 配置)。
56
36
 
57
- **适用场景:** 工具类、枚举类、POJO、算法逻辑(无需 Spring 容器)
37
+ ---
58
38
 
59
- **特点:** 不使用 `@SpringBootTest`,执行速度快,适合纯逻辑测试。
39
+ ## 1. 单元测试(纯 JUnit5,无 Spring)
60
40
 
61
41
  ```java
62
42
  package org.dromara.test;
@@ -65,164 +45,35 @@ import org.junit.jupiter.api.Assertions;
65
45
  import org.junit.jupiter.api.DisplayName;
66
46
  import org.junit.jupiter.api.Test;
67
47
 
68
- /**
69
- * 断言单元测试案例
70
- * 参考:ruoyi-admin/src/test/java/org/dromara/test/AssertUnitTest.java
71
- */
72
- @DisplayName("断言单元测试案例")
73
- public class AssertUnitTest {
74
-
75
- @Test
76
- @DisplayName("测试 assertEquals 方法")
77
- public void testAssertEquals() {
78
- Assertions.assertEquals("666", new String("666"));
79
- Assertions.assertNotEquals("777", new String("666"));
80
- }
81
-
82
- @Test
83
- @DisplayName("测试 assertTrue 方法")
84
- public void testAssertTrue() {
85
- Assertions.assertTrue(true);
86
- Assertions.assertFalse(false);
87
- }
88
-
89
- @Test
90
- @DisplayName("测试 assertNull 方法")
91
- public void testAssertNull() {
92
- Assertions.assertNull(null);
93
- Assertions.assertNotNull("not null");
94
- }
95
- }
96
- ```
97
-
98
- **常用断言方法:**
99
-
100
- ```java
101
- // 相等性断言
102
- Assertions.assertEquals(expected, actual);
103
- Assertions.assertNotEquals(expected, actual);
104
-
105
- // 同一性断言
106
- Assertions.assertSame(obj1, obj2);
107
- Assertions.assertNotSame(obj1, obj2);
108
-
109
- // 布尔断言
110
- Assertions.assertTrue(condition);
111
- Assertions.assertFalse(condition);
112
-
113
- // 空值断言
114
- Assertions.assertNull(object);
115
- Assertions.assertNotNull(object);
116
-
117
- // 异常断言
118
- Assertions.assertThrows(Exception.class, () -> {
119
- // 会抛出异常的代码
120
- });
121
- ```
122
-
123
- ---
124
-
125
- ## 2. Spring 集成测试(@SpringBootTest)
126
-
127
- **适用场景:** 需要 Spring 容器的测试(Service、Controller、Mapper、需要依赖注入的场景)
128
-
129
- **特点:** 使用 `@SpringBootTest` 启动完整的 Spring 容器,可以使用 `@Autowired` 注入 Bean。
130
-
131
- **重要提示:** `@SpringBootTest` 只能在 SpringBoot 主包下使用,需包含 main 方法与 yml 配置文件。
132
-
133
- ```java
134
- package org.dromara.test;
135
-
136
- import org.dromara.common.web.config.properties.CaptchaProperties;
137
- import org.junit.jupiter.api.*;
138
- import org.springframework.beans.factory.annotation.Autowired;
139
- import org.springframework.boot.test.context.SpringBootTest;
140
-
141
- import java.util.concurrent.TimeUnit;
142
-
143
- /**
144
- * Spring 集成测试案例
145
- * 参考:ruoyi-admin/src/test/java/org/dromara/test/DemoUnitTest.java
146
- */
147
- @SpringBootTest
148
- @DisplayName("单元测试案例")
149
- public class DemoUnitTest {
150
-
151
- @Autowired
152
- private CaptchaProperties captchaProperties;
153
-
154
- @Test
155
- @DisplayName("测试 @SpringBootTest @Test @DisplayName 注解")
156
- public void testTest() {
157
- System.out.println(captchaProperties);
158
- Assertions.assertNotNull(captchaProperties);
159
- }
48
+ @DisplayName("StringUtils 测试")
49
+ public class StringUtilsTest {
160
50
 
161
51
  @Test
162
- @DisplayName("测试 @Disabled 注解")
163
- @Disabled // 禁用此测试
164
- public void testDisabled() {
165
- System.out.println("此测试被禁用");
52
+ @DisplayName("测试 isBlank 方法")
53
+ public void testIsBlank() {
54
+ Assertions.assertTrue(StringUtils.isBlank(null));
55
+ Assertions.assertTrue(StringUtils.isBlank(""));
56
+ Assertions.assertFalse(StringUtils.isBlank("hello"));
166
57
  }
167
58
 
168
59
  @Test
169
- @DisplayName("测试 @Timeout 注解")
170
- @Timeout(value = 2L, unit = TimeUnit.SECONDS)
171
- public void testTimeout() throws InterruptedException {
172
- Thread.sleep(1000); // 1秒,不会超时
173
- }
174
-
175
- @RepeatedTest(3)
176
- @DisplayName("测试 @RepeatedTest 注解")
177
- public void testRepeatedTest() {
178
- System.out.println("重复测试");
179
- }
180
-
181
- @BeforeAll
182
- public static void testBeforeAll() {
183
- System.out.println("@BeforeAll - 所有测试前执行一次");
184
- }
185
-
186
- @BeforeEach
187
- public void testBeforeEach() {
188
- System.out.println("@BeforeEach - 每个测试前执行");
189
- }
190
-
191
- @AfterEach
192
- public void testAfterEach() {
193
- System.out.println("@AfterEach - 每个测试后执行");
194
- }
195
-
196
- @AfterAll
197
- public static void testAfterAll() {
198
- System.out.println("@AfterAll - 所有测试后执行一次");
60
+ @DisplayName("测试异常抛出")
61
+ public void testThrowsException() {
62
+ Assertions.assertThrows(NullPointerException.class, () -> {
63
+ String str = null;
64
+ str.length();
65
+ });
199
66
  }
200
67
  }
201
68
  ```
202
69
 
203
70
  ---
204
71
 
205
- ## 3. Service 测试(@SpringBootTest + @Transactional)
206
-
207
- **适用场景:** Service 层业务逻辑测试,需要数据库操作
208
-
209
- **特点:** 使用 `@SpringBootTest` + `@Transactional`,测试后自动回滚,不污染数据库。
72
+ ## 2. Service 集成测试
210
73
 
211
74
  ```java
212
- package org.dromara.demo.service;
213
-
214
- import org.dromara.demo.domain.bo.TestDemoBo;
215
- import org.dromara.demo.domain.vo.TestDemoVo;
216
- import org.junit.jupiter.api.*;
217
- import org.springframework.beans.factory.annotation.Autowired;
218
- import org.springframework.boot.test.context.SpringBootTest;
219
- import org.springframework.transaction.annotation.Transactional;
220
-
221
- /**
222
- * Service 层测试示例
223
- */
224
75
  @SpringBootTest
225
- @Transactional // 测试后自动回滚
76
+ @Transactional // 测试后自动回滚,不污染数据库
226
77
  @DisplayName("TestDemo Service 测试")
227
78
  public class TestDemoServiceTest {
228
79
 
@@ -232,66 +83,36 @@ public class TestDemoServiceTest {
232
83
  @Test
233
84
  @DisplayName("测试添加数据")
234
85
  public void testAdd() {
235
- // Arrange - 准备数据
86
+ // Arrange
236
87
  TestDemoBo bo = new TestDemoBo();
237
88
  bo.setDeptId(103L);
238
89
  bo.setUserId(1L);
239
- bo.setOrderNum(1);
240
90
  bo.setTestKey("测试数据");
241
91
  bo.setValue("test_value");
242
92
 
243
- // Act - 执行操作
93
+ // Act
244
94
  Boolean result = testDemoService.insertByBo(bo);
245
95
 
246
- // Assert - 验证结果
96
+ // Assert
247
97
  Assertions.assertTrue(result);
248
98
  }
249
99
 
250
100
  @Test
251
101
  @DisplayName("测试查询详情")
252
102
  public void testGetById() {
253
- // 先添加测试数据
254
103
  TestDemoBo bo = new TestDemoBo();
255
- bo.setDeptId(103L);
256
- bo.setUserId(1L);
257
- bo.setOrderNum(2);
258
104
  bo.setTestKey("测试查询");
259
105
  bo.setValue("test_query");
260
106
  testDemoService.insertByBo(bo);
261
107
 
262
- // 查询详情
263
108
  TestDemoVo vo = testDemoService.queryById(bo.getId());
264
-
265
- // 断言
266
109
  Assertions.assertNotNull(vo);
267
110
  Assertions.assertEquals("测试查询", vo.getTestKey());
268
111
  }
269
-
270
- @Test
271
- @DisplayName("测试更新数据")
272
- public void testUpdate() {
273
- // 先添加测试数据
274
- TestDemoBo bo = new TestDemoBo();
275
- bo.setDeptId(103L);
276
- bo.setUserId(1L);
277
- bo.setOrderNum(3);
278
- bo.setTestKey("原始名称");
279
- bo.setValue("original");
280
- testDemoService.insertByBo(bo);
281
-
282
- // 更新数据
283
- bo.setTestKey("更新后名称");
284
- Boolean result = testDemoService.updateByBo(bo);
285
-
286
- // 验证
287
- Assertions.assertTrue(result);
288
- TestDemoVo vo = testDemoService.queryById(bo.getId());
289
- Assertions.assertEquals("更新后名称", vo.getTestKey());
290
- }
291
112
  }
292
113
  ```
293
114
 
294
- **Mock 外部依赖示例:**
115
+ ### Mock 外部依赖
295
116
 
296
117
  ```java
297
118
  @SpringBootTest
@@ -301,21 +122,17 @@ public class OrderServiceTest {
301
122
  @Autowired
302
123
  private IOrderService orderService;
303
124
 
304
- @MockBean // Mock 支付服务
125
+ @MockBean
305
126
  private IPaymentService paymentService;
306
127
 
307
128
  @Test
308
129
  @DisplayName("测试订单支付(Mock 支付服务)")
309
130
  public void testPayOrder() {
310
131
  Long orderId = 123L;
311
-
312
- // Mock 行为
313
132
  Mockito.when(paymentService.pay(orderId)).thenReturn(true);
314
133
 
315
- // 执行
316
134
  Boolean success = orderService.payOrder(orderId);
317
135
 
318
- // 断言
319
136
  Assertions.assertTrue(success);
320
137
  Mockito.verify(paymentService, Mockito.times(1)).pay(orderId);
321
138
  }
@@ -324,28 +141,9 @@ public class OrderServiceTest {
324
141
 
325
142
  ---
326
143
 
327
- ## 4. Controller 测试(@SpringBootTest + MockMvc)
328
-
329
- **适用场景:** HTTP 接口测试,完整请求链路
330
-
331
- **特点:** 使用 `@SpringBootTest` + `@AutoConfigureMockMvc`,模拟 HTTP 请求。
144
+ ## 3. Controller 测试
332
145
 
333
146
  ```java
334
- package org.dromara.demo.controller;
335
-
336
- import org.junit.jupiter.api.*;
337
- import org.springframework.beans.factory.annotation.Autowired;
338
- import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
339
- import org.springframework.boot.test.context.SpringBootTest;
340
- import org.springframework.http.MediaType;
341
- import org.springframework.test.web.servlet.MockMvc;
342
-
343
- import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
344
- import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
345
-
346
- /**
347
- * Controller 层测试示例
348
- */
349
147
  @SpringBootTest
350
148
  @AutoConfigureMockMvc
351
149
  @DisplayName("TestDemo Controller 测试")
@@ -364,14 +162,6 @@ public class TestDemoControllerTest {
364
162
  .andExpect(jsonPath("$.code").value(200));
365
163
  }
366
164
 
367
- @Test
368
- @DisplayName("测试查询详情")
369
- public void testGetById() throws Exception {
370
- mockMvc.perform(get("/demo/demo/1"))
371
- .andExpect(status().isOk())
372
- .andExpect(jsonPath("$.code").value(200));
373
- }
374
-
375
165
  @Test
376
166
  @DisplayName("测试添加数据")
377
167
  public void testAdd() throws Exception {
@@ -379,7 +169,6 @@ public class TestDemoControllerTest {
379
169
  {
380
170
  "deptId": 103,
381
171
  "userId": 1,
382
- "orderNum": 1,
383
172
  "testKey": "测试数据",
384
173
  "value": "test_value"
385
174
  }
@@ -391,365 +180,122 @@ public class TestDemoControllerTest {
391
180
  .andExpect(status().isOk())
392
181
  .andExpect(jsonPath("$.code").value(200));
393
182
  }
394
-
395
- @Test
396
- @DisplayName("测试更新数据")
397
- public void testUpdate() throws Exception {
398
- String requestBody = """
399
- {
400
- "id": 1,
401
- "deptId": 103,
402
- "userId": 1,
403
- "orderNum": 1,
404
- "testKey": "更新后数据",
405
- "value": "updated_value"
406
- }
407
- """;
408
-
409
- mockMvc.perform(put("/demo/demo")
410
- .contentType(MediaType.APPLICATION_JSON)
411
- .content(requestBody))
412
- .andExpect(status().isOk())
413
- .andExpect(jsonPath("$.code").value(200));
414
- }
415
-
416
- @Test
417
- @DisplayName("测试删除数据")
418
- public void testDelete() throws Exception {
419
- mockMvc.perform(delete("/demo/demo/1,2,3"))
420
- .andExpect(status().isOk())
421
- .andExpect(jsonPath("$.code").value(200));
422
- }
423
183
  }
424
184
  ```
425
185
 
426
186
  ---
427
187
 
428
- ## 5. 参数化测试
429
-
430
- **适用场景:** 需要用多组数据测试同一个方法
431
-
432
- **特点:** 使用 `@ParameterizedTest` 替代 `@Test`,配合数据源注解提供测试数据。
188
+ ## 4. 参数化测试
433
189
 
434
190
  ```java
435
- package org.dromara.test;
436
-
437
- import org.dromara.common.core.enums.UserType;
438
- import org.junit.jupiter.api.*;
439
- import org.junit.jupiter.params.ParameterizedTest;
440
- import org.junit.jupiter.params.provider.*;
441
-
442
- import java.util.ArrayList;
443
- import java.util.List;
444
- import java.util.stream.Stream;
445
-
446
- /**
447
- * 参数化测试案例
448
- * 参考:ruoyi-admin/src/test/java/org/dromara/test/ParamUnitTest.java
449
- */
450
- @DisplayName("带参数单元测试案例")
191
+ @DisplayName("参数化测试")
451
192
  public class ParamUnitTest {
452
193
 
453
194
  @ParameterizedTest
454
- @DisplayName("测试 @ValueSource 注解")
455
195
  @ValueSource(strings = {"t1", "t2", "t3"})
456
196
  public void testValueSource(String str) {
457
- System.out.println(str);
458
197
  Assertions.assertNotNull(str);
459
198
  }
460
199
 
461
200
  @ParameterizedTest
462
- @DisplayName("测试 @NullSource 注解")
463
- @NullSource
464
- public void testNullSource(String str) {
465
- System.out.println(str);
466
- Assertions.assertNull(str);
467
- }
468
-
469
- @ParameterizedTest
470
- @DisplayName("测试 @EnumSource 注解")
471
201
  @EnumSource(UserType.class)
472
202
  public void testEnumSource(UserType type) {
473
- System.out.println(type.getUserType());
474
203
  Assertions.assertNotNull(type);
475
204
  }
476
205
 
477
206
  @ParameterizedTest
478
- @DisplayName("测试 @MethodSource 注解")
207
+ @CsvSource({"1, Banner, 横幅广告", "2, Popup, 弹窗广告"})
208
+ public void testCsvData(String code, String name, String desc) {
209
+ Assertions.assertNotNull(code);
210
+ }
211
+
212
+ @ParameterizedTest
479
213
  @MethodSource("getParam")
480
214
  public void testMethodSource(String str) {
481
- System.out.println(str);
482
215
  Assertions.assertNotNull(str);
483
216
  }
484
217
 
485
218
  public static Stream<String> getParam() {
486
- List<String> list = new ArrayList<>();
487
- list.add("t1");
488
- list.add("t2");
489
- list.add("t3");
490
- return list.stream();
219
+ return Stream.of("t1", "t2", "t3");
491
220
  }
492
-
493
- @BeforeEach
494
- public void testBeforeEach() {
495
- System.out.println("@BeforeEach - 每个测试前执行");
496
- }
497
-
498
- @AfterEach
499
- public void testAfterEach() {
500
- System.out.println("@AfterEach - 每个测试后执行");
501
- }
502
- }
503
- ```
504
-
505
- **更多参数化测试示例:**
506
-
507
- ```java
508
- // CSV 数据源
509
- @ParameterizedTest
510
- @DisplayName("测试 CSV 数据")
511
- @CsvSource({
512
- "1, Banner, 横幅广告",
513
- "2, Popup, 弹窗广告"
514
- })
515
- public void testCsvData(String code, String name, String desc) {
516
- Assertions.assertNotNull(code);
517
- Assertions.assertNotNull(name);
518
- }
519
-
520
- // 多个值源
521
- @ParameterizedTest
522
- @DisplayName("测试多个整数")
523
- @ValueSource(ints = {1, 2, 3, 4, 5})
524
- public void testIntValues(int num) {
525
- Assertions.assertTrue(num > 0);
526
221
  }
527
-
528
- // 空值和空字符串
529
- @ParameterizedTest
530
- @DisplayName("测试空值")
531
- @NullAndEmptySource
532
- @ValueSource(strings = {" ", "\t", "\n"})
533
- public void testBlankStrings(String input) {
534
- Assertions.assertTrue(input == null || input.isBlank());
535
- }
536
- ```
537
-
538
- ---
539
-
540
- ## 6. 测试标签和分组(@Tag)
541
-
542
- **适用场景:** 需要对测试进行分组,选择性运行某些测试
543
-
544
- **特点:** 使用 `@Tag` 注解标记测试,可以按标签过滤执行。
545
-
546
- ```java
547
- package org.dromara.test;
548
-
549
- import org.junit.jupiter.api.*;
550
- import org.springframework.boot.test.context.SpringBootTest;
551
-
552
- /**
553
- * 标签单元测试案例
554
- * 参考:ruoyi-admin/src/test/java/org/dromara/test/TagUnitTest.java
555
- */
556
- @SpringBootTest
557
- @DisplayName("标签单元测试案例")
558
- public class TagUnitTest {
559
-
560
- @Test
561
- @Tag("dev")
562
- @DisplayName("测试 @Tag dev")
563
- public void testTagDev() {
564
- System.out.println("dev 环境测试");
565
- }
566
-
567
- @Test
568
- @Tag("prod")
569
- @DisplayName("测试 @Tag prod")
570
- public void testTagProd() {
571
- System.out.println("prod 环境测试");
572
- }
573
-
574
- @Test
575
- @Tag("local")
576
- @DisplayName("测试 @Tag local")
577
- public void testTagLocal() {
578
- System.out.println("local 环境测试");
579
- }
580
-
581
- @Test
582
- @Tag("exclude")
583
- @DisplayName("测试 @Tag exclude")
584
- public void testTagExclude() {
585
- System.out.println("排除的测试");
586
- }
587
-
588
- @BeforeEach
589
- public void testBeforeEach() {
590
- System.out.println("@BeforeEach - 每个测试前执行");
591
- }
592
-
593
- @AfterEach
594
- public void testAfterEach() {
595
- System.out.println("@AfterEach - 每个测试后执行");
596
- }
597
- }
598
- ```
599
-
600
- **运行指定标签的测试:**
601
-
602
- ```bash
603
- # Maven 运行指定标签的测试
604
- mvn test -Dgroups=dev
605
-
606
- # Maven 排除指定标签的测试
607
- mvn test -DexcludedGroups=exclude
608
-
609
- # IDEA 中配置标签过滤
610
- # Run → Edit Configurations → Test kind: Tags → Tag expression: dev
611
222
  ```
612
223
 
613
- ---
614
-
615
- ## 开发检查清单
616
-
617
- ### 测试文件规范
618
-
619
- - [ ] **测试类命名**:`{被测试类名}Test`(如 `StringUtilsTest`、`DemoUnitTest`)
620
- - [ ] **测试类位置**:`src/test/java` 目录下,包路径与源码一致
621
- - [ ] **测试方法命名**:`test{功能}`(如 `testIsBlank`、`testAdd`)
622
- - [ ] **使用 @DisplayName**:为测试类和方法添加中文描述
623
-
624
- ### 注解选择
625
-
626
- - [ ] **纯单元测试**:不使用 `@SpringBootTest`,适合工具类/枚举/POJO
627
- - [ ] **集成测试**:使用 `@SpringBootTest`,适合 Service/Controller/Mapper
628
- - [ ] **Service 测试**:使用 `@SpringBootTest` + `@Transactional`,测试后自动回滚
629
- - [ ] **Controller 测试**:使用 `@SpringBootTest` + `@AutoConfigureMockMvc`
630
-
631
- ### 断言规范
632
-
633
- - [ ] **使用 JUnit5 Assertions**:`Assertions.assertEquals()` / `Assertions.assertTrue()` 等
634
- - [ ] **异常断言**:`Assertions.assertThrows(Exception.class, () -> {...})`
635
- - [ ] **空值断言**:`Assertions.assertNull()` / `Assertions.assertNotNull()`
636
-
637
- ### Mock 规范
638
-
639
- - [ ] **Spring 测试**:使用 `@MockBean` Mock Spring Bean
640
- - [ ] **单元测试**:使用 `@Mock` / `@InjectMocks`(Mockito)
641
- - [ ] **验证调用**:使用 `Mockito.verify()` 验证 Mock 方法被调用
224
+ > 更多参数化测试示例详见 `references/parameterized-examples.md`
642
225
 
643
226
  ---
644
227
 
645
- ## 常见错误
646
-
647
- | 错误写法 | 正确写法 | 原因 |
648
- |---------|---------|------|
649
- | 测试类在 `src/main/java` | 测试类在 `src/test/java` | 测试代码不应打包到生产环境 |
650
- | `@Test public void test()` | `@Test @DisplayName("xxx") public void testXxx()` | 缺少描述和命名规范 |
651
- | 忘记添加 `@SpringBootTest` | 需要依赖注入时添加 `@SpringBootTest` | 无法注入 Spring Bean |
652
- | `@SpringBootTest` 在非主包下 | 测试类必须在主包下(包含 main 方法) | `@SpringBootTest` 需要找到主类 |
653
- | Mock 后不验证调用 | `Mockito.verify(mockObj).method()` | Mock 应验证调用次数和参数 |
654
- | 测试方法相互依赖 | 每个测试方法独立 | 测试应独立可并行执行 |
655
- | Service 测试不加 `@Transactional` | 使用 `@Transactional` 自动回滚 | 避免污染数据库 |
656
- | 硬编码测试数据 | 使用变量或常量 | 提高可维护性 |
657
-
658
- ---
659
-
660
- ## 异常测试
661
-
662
- **适用场景:** 测试方法是否正确抛出异常
228
+ ## 5. 异常测试
663
229
 
664
230
  ```java
665
- import org.dromara.common.core.exception.ServiceException;
666
- import org.junit.jupiter.api.Assertions;
667
- import org.junit.jupiter.api.DisplayName;
668
- import org.junit.jupiter.api.Test;
669
-
670
231
  @Test
671
- @DisplayName("测试添加数据 - key键为空抛出异常")
232
+ @DisplayName("测试 key 为空抛出异常")
672
233
  public void testAdd_ThrowsException() {
673
234
  TestDemoBo bo = new TestDemoBo();
674
- // 不设置 testKey(必填字段)
235
+ // 不设置必填字段
675
236
 
676
- // 断言抛出 ServiceException 异常
677
237
  ServiceException exception = Assertions.assertThrows(
678
238
  ServiceException.class,
679
239
  () -> testDemoService.insertByBo(bo)
680
240
  );
681
-
682
- // 验证异常消息
683
241
  Assertions.assertTrue(exception.getMessage().contains("key键不能为空"));
684
242
  }
685
-
686
- @Test
687
- @DisplayName("测试空指针异常")
688
- public void testNullPointerException() {
689
- Assertions.assertThrows(
690
- NullPointerException.class,
691
- () -> {
692
- String str = null;
693
- str.length();
694
- }
695
- );
696
- }
697
243
  ```
698
244
 
699
245
  ---
700
246
 
701
- ## 运行测试
247
+ ## 6. 测试标签(@Tag)
702
248
 
703
- ```bash
704
- # Maven 运行所有测试
705
- mvn test
706
-
707
- # Maven 运行单个测试类
708
- mvn test -Dtest=AdServiceTest
709
-
710
- # Maven 运行单个测试方法
711
- mvn test -Dtest=AdServiceTest#testAddAd
249
+ ```java
250
+ @Test @Tag("dev") public void testDev() { }
251
+ @Test @Tag("prod") public void testProd() { }
252
+ ```
712
253
 
713
- # IDEA 中运行
714
- # 右键测试类/方法 Run 'XXTest'
254
+ ```bash
255
+ mvn test -Dgroups=dev # 运行 dev 标签
256
+ mvn test -DexcludedGroups=prod # 排除 prod 标签
715
257
  ```
716
258
 
717
259
  ---
718
260
 
719
- ## FAQ
720
-
721
- ### Q1: 什么时候使用 @SpringBootTest?
722
-
723
- **A:**
724
- - **不使用 @SpringBootTest**:工具类、枚举、POJO(纯逻辑测试,不需要 Spring 容器)
725
- - **使用 @SpringBootTest**:Service、Controller、Mapper(需要依赖注入和 Spring 容器)
726
-
727
- ### Q2: Service 测试会污染数据库吗?
728
-
729
- **A:** 不会。使用 `@SpringBootTest` + `@Transactional`,测试结束后自动回滚,不会污染数据库。
730
-
731
- ### Q3: 如何测试私有方法?
732
-
733
- **A:**
734
- - 不要直接测试私有方法
735
- - 通过公共方法间接测试
736
- - 如果私有方法太复杂,考虑提取为独立类
261
+ ## 运行测试
737
262
 
738
- ### Q4: Mock 和真实测试如何选择?
263
+ ```bash
264
+ mvn test # 运行所有测试
265
+ mvn test -Dtest=AdServiceTest # 运行单个测试类
266
+ mvn test -Dtest=AdServiceTest#testAddAd # 运行单个方法
267
+ mvn clean install -DskipTests # 跳过测试
268
+ ```
739
269
 
740
- **A:**
741
- - **单元测试**: 优先 Mock 外部依赖(快速、隔离)
742
- - **集成测试**: 使用真实依赖(准确、完整)
743
- - **平衡**: 既要有单元测试(快),也要有集成测试(准确)
270
+ ---
744
271
 
745
- ### Q5: @SpringBootTest 为什么找不到主类?
272
+ ## 开发检查清单
746
273
 
747
- **A:** `@SpringBootTest` 只能在 SpringBoot 主包下使用,测试类必须与主类(包含 main 方法)在同一个包或子包下。
274
+ ### 命名规范
748
275
 
749
- ### Q6: 如何跳过测试执行?
276
+ - [ ] 测试类:`{被测试类名}Test`
277
+ - [ ] 测试方法:`test{功能}`
278
+ - [ ] 使用 `@DisplayName` 添加中文描述
279
+ - [ ] 位于 `src/test/java`,包路径与源码一致
750
280
 
751
- **A:**
752
- - **单个测试**:使用 `@Disabled` 注解
753
- - **Maven 跳过所有测试**:`mvn clean install -DskipTests`
281
+ ### 注解选择
754
282
 
755
- ---
283
+ | 场景 | 注解组合 |
284
+ |------|---------|
285
+ | 工具类/枚举/POJO | 不加 `@SpringBootTest` |
286
+ | Service 测试 | `@SpringBootTest` + `@Transactional` |
287
+ | Controller 测试 | `@SpringBootTest` + `@AutoConfigureMockMvc` |
288
+ | Mock Spring Bean | `@MockBean` |
289
+ | Mock(纯单元测试) | `@Mock` + `@InjectMocks` |
290
+
291
+ ### 常见错误
292
+
293
+ | 错误 | 正确做法 |
294
+ |------|---------|
295
+ | 测试在 `src/main/java` | 放到 `src/test/java` |
296
+ | 缺少 `@DisplayName` | 必须添加描述 |
297
+ | 需要注入但没加 `@SpringBootTest` | 加上注解 |
298
+ | `@SpringBootTest` 在非主包下 | 确保在主类同包或子包 |
299
+ | Mock 后不验证调用 | `Mockito.verify()` |
300
+ | 测试方法相互依赖 | 每个测试独立 |
301
+ | Service 测试不加 `@Transactional` | 加上防止污染数据库 |