springboot-verification

Automated verification pipeline for Spring Boot projects: build, static analysis, tests with coverage, security scans, and diff review. Runs six sequential phases: Maven/Gradle build, static analysis (SpotBugs, PMD, Checkstyle), unit and integration tests with JaCoCo coverage reporting, dependency CVE scanning, optional code formatting, and git diff review Supports both Maven and Gradle with parallel build acceleration ( -T 4 flag) and includes example test patterns for unit tests, Testcontainers integration tests, and MockMvc API tests Detects common security issues: hardcoded secrets, System.out logging, raw exception messages in responses, and wildcard CORS configurations Generates structured verification report with pass/fail status per phase and actionable issue list for pre-PR and pre-deployment gates

INSTALLATION
npx skills add https://github.com/affaan-m/everything-claude-code --skill springboot-verification
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

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

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):

mvn -T 4 spotbugs:check pmd:check checkstyle:check

Gradle (if configured):

./gradlew checkstyleMain pmdMain spotbugsMain

Phase 3: Tests + Coverage

mvn -T 4 test

mvn 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:

@ExtendWith(MockitoExtension.class)

class UserServiceTest {

  @Mock private UserRepository userRepository;

  @InjectMocks private UserService userService;

  @Test

  void 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));

  }

  @Test

  void 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:

@SpringBootTest

@Testcontainers

class UserRepositoryIntegrationTest {

  @Container

  static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine")

      .withDatabaseName("testdb");

  @DynamicPropertySource

  static 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;

  @Test

  void 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:

@WebMvcTest(UserController.class)

class UserControllerTest {

  @Autowired private MockMvc mockMvc;

  @MockBean private UserService userService;

  @Test

  void 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"));

  }

  @Test

  void 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

# Dependency CVEs

mvn org.owasp:dependency-check-maven:check

# or

./gradlew dependencyCheckAnalyze

# Secrets in source

grep -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 responses

grep -rn "e\.getMessage()" src/main/ --include="*.java"

# Check for wildcard CORS

grep -rn "allowedOrigins.*\*" src/main/ --include="*.java"

Phase 5: Lint/Format (optional gate)

mvn spotless:apply   # if using Spotless plugin

./gradlew spotlessApply

Phase 6: Diff Review

git diff --stat

git diff

Checklist:

  • No debugging logs left (System.out, log.debug without 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.

BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card