<< All versions
Skill v1.0.2
currentAutomated scan96/100loulanyue/awesome-claude-notes/springboot-verification
~1 modified
──Details
PublishedJuly 5, 2026 at 02:41 AM
Content Hashsha256:6246a88e4a2bccc9...
Git SHA47bbbc2d715e
Bump Typepatch
──Files
Files (1 file, 5.9 KB)
SKILL.md5.9 KBactive
SKILL.md · 241 lines · 5.9 KB
version: "1.0.2" name: springboot-verification description: "Verification loop for Spring Boot projects: build, static analysis, tests with coverage, security scans, and diff review before release or PR." source_path: skills/springboot-verification/SKILL.md origin: ECC
Spring Boot Verification Loop
Run before PRs, after major changes, and pre-deploy.
When to Activate
- Before opening a pull request for a Spring Boot service
- After major refactoring or dependency upgrades
- Pre-deployment verification for staging or production
- Running full build → lint → test → security scan pipeline
- Validating test coverage meets thresholds
Phase 1: Build
bash
mvn -T 4 clean verify -DskipTests# or./gradlew clean assemble -x test
If build fails, stop and fix.
Phase 2: Static Analysis
Maven (common plugins):
bash
mvn -T 4 spotbugs:check pmd:check checkstyle:check
Gradle (if configured):
bash
./gradlew checkstyleMain pmdMain spotbugsMain
Phase 3: Tests + Coverage
bash
mvn -T 4 testmvn jacoco:report # verify 80%+ coverage# or./gradlew test jacocoTestReport
Report:
- Total tests, passed/failed
- Coverage % (lines/branches)
Unit Tests
Test service logic in isolation with mocked dependencies:
java
@ExtendWith(MockitoExtension.class)class UserServiceTest {@Mock private UserRepository userRepository;@InjectMocks private UserService userService;@Testvoid createUser_validInput_returnsUser() {var dto = new CreateUserDto("Alice", "alice@example.com");var expected = new User(1L, "Alice", "alice@example.com");when(userRepository.save(any(User.class))).thenReturn(expected);var result = userService.create(dto);assertThat(result.name()).isEqualTo("Alice");verify(userRepository).save(any(User.class));}@Testvoid createUser_duplicateEmail_throwsException() {var dto = new CreateUserDto("Alice", "existing@example.com");when(userRepository.existsByEmail(dto.email())).thenReturn(true);assertThatThrownBy(() -> userService.create(dto)).isInstanceOf(DuplicateEmailException.class);}}
Integration Tests with Testcontainers
Test against a real database instead of H2:
java
@SpringBootTest@Testcontainersclass UserRepositoryIntegrationTest {@Containerstatic PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine").withDatabaseName("testdb");@DynamicPropertySourcestatic void configureProperties(DynamicPropertyRegistry registry) {registry.add("spring.datasource.url", postgres::getJdbcUrl);registry.add("spring.datasource.username", postgres::getUsername);registry.add("spring.datasource.password", postgres::getPassword);}@Autowired private UserRepository userRepository;@Testvoid findByEmail_existingUser_returnsUser() {userRepository.save(new User("Alice", "alice@example.com"));var found = userRepository.findByEmail("alice@example.com");assertThat(found).isPresent();assertThat(found.get().getName()).isEqualTo("Alice");}}
API Tests with MockMvc
Test controller layer with full Spring context:
java
@WebMvcTest(UserController.class)class UserControllerTest {@Autowired private MockMvc mockMvc;@MockBean private UserService userService;@Testvoid createUser_validInput_returns201() throws Exception {var user = new UserDto(1L, "Alice", "alice@example.com");when(userService.create(any())).thenReturn(user);mockMvc.perform(post("/api/users").contentType(MediaType.APPLICATION_JSON).content("""{"name": "Alice", "email": "alice@example.com"}""")).andExpect(status().isCreated()).andExpect(jsonPath("$.name").value("Alice"));}@Testvoid createUser_invalidEmail_returns400() throws Exception {mockMvc.perform(post("/api/users").contentType(MediaType.APPLICATION_JSON).content("""{"name": "Alice", "email": "not-an-email"}""")).andExpect(status().isBadRequest());}}
Phase 4: Security Scan
bash
# Dependency CVEsmvn org.owasp:dependency-check-maven:check# or./gradlew dependencyCheckAnalyze# Secrets in sourcegrep -rn "password\s*=\s*\"" src/ --include="*.java" --include="*.yml" --include="*.properties"grep -rn "sk-\|api_key\|secret" src/ --include="*.java" --include="*.yml"# Secrets (git history)git secrets --scan # if configured
Common Security Findings
# Check for System.out.println (use logger instead)grep -rn "System\.out\.print" src/main/ --include="*.java"# Check for raw exception messages in responsesgrep -rn "e\.getMessage()" src/main/ --include="*.java"# Check for wildcard CORSgrep -rn "allowedOrigins.*\*" src/main/ --include="*.java"
Phase 5: Lint/Format (optional gate)
bash
mvn spotless:apply # if using Spotless plugin./gradlew spotlessApply
Phase 6: Diff Review
bash
git diff --statgit diff
Checklist:
- No debugging logs left (
System.out,log.debugwithout guards) - Meaningful errors and HTTP statuses
- Transactions and validation present where needed
- Config changes documented
Output Template
VERIFICATION REPORT===================Build: [PASS/FAIL]Static: [PASS/FAIL] (spotbugs/pmd/checkstyle)Tests: [PASS/FAIL] (X/Y passed, Z% coverage)Security: [PASS/FAIL] (CVE findings: N)Diff: [X files changed]Overall: [READY / NOT READY]Issues to Fix:1. ...2. ...
Continuous Mode
- Re-run phases on significant changes or every 30–60 minutes in long sessions
- Keep a short loop:
mvn -T 4 test+ spotbugs for quick feedback
Remember: Fast feedback beats late surprises. Keep the gate strict—treat warnings as defects in production systems.