The first time I asked an AI assistant to generate tests for a service class, it gave me fifteen green tests that verified almost nothing — assertNotNull on every line, mocks returning values no production system would produce, and not a single boundary case. The tests passed; they just didn’t protect anything. What changed the output quality wasn’t a better model — it was a better prompt: one that pinned the JUnit version, demanded specific annotations, listed the scenarios that had to be covered, and forced meaningful assertions.
This post collects the 10 prompts for generating JUnit 6 tests that came out of that process — refined across real projects until the output was something I could commit after a review pass rather than a rewrite. They work with GitHub Copilot, Claude, ChatGPT, JetBrains AI, or any capable LLM. Tested against Claude Sonnet 4 and GPT-4o, generating tests for JUnit 6.0 with Mockito 5.x and Spring Boot 3.4.
For background on JUnit 6 test structure, see the JUnit 6 Tutorial Series. For best practices on what makes a test maintainable, see Writing Your First Clean Test in JUnit 6.
Getting Commit-Ready Tests from These Prompts
Two habits separate output you can commit from output you spend an hour rewriting. First, pin the framework versions in the prompt — “JUnit 6.0, Mockito 5.12, Spring Boot 3.4” — because assertion APIs and extension wiring differ enough between generations that an unpinned prompt often returns JUnit 4 runners or deprecated Mockito calls. Second, replace every [SQUARE BRACKET] placeholder with your real code: paste the actual class, the actual Javadoc, the actual business rules. Generic placeholder input produces generic placeholder tests — the AI mirrors the specificity you give it.
Always review AI-generated tests with this checklist:
- Does every assertion have a meaningful message?
- Does the test name accurately describe the behaviour?
- Are the mocked return values realistic?
- Does the test follow Arrange-Act-Assert structure?
- Would it fail if the corresponding production code had the bug it is meant to catch?
Prompt 1: Complete Unit Test Class for a Service
When to use: You have written a new service class and want a full suite of unit tests generated from scratch.
Generate a complete JUnit 6 unit test class for the following Java service class.
Requirements:
- Use @ExtendWith(MockitoExtension.class)
- Use @Mock for all dependencies, @InjectMocks for the class under test
- Use @DisplayName with a full English sentence on every @Test method
- Follow Arrange-Act-Assert with a blank line between each phase
- Include tests for: happy path, null input, empty input, boundary values, and exception throwing
- Use assertAll() when verifying multiple properties on one object
- Use assertThrows() for exception tests and verify the exception message
- Add @Tag("unit") on every test method
Production class to test:
[PASTE YOUR SERVICE CLASS HERE]
Prompt 2: Parameterized Tests for Validation Logic
When to use: Your class validates input (email, phone, postcode, password) and you want comprehensive data-driven tests covering valid, invalid, and edge-case inputs.
Generate JUnit 6 @ParameterizedTest methods for the following validator class.
Requirements:
- Use @ParameterizedTest with a descriptive name= attribute showing the input
- Use @CsvSource for multiple-column cases (input, expected result)
- Use @NullAndEmptySource combined with @ValueSource for blank input edge cases
- Use @EnumSource if any enum values are relevant
- Include at least 8 test cases covering: valid inputs, invalid formats, null, empty string,
whitespace-only, unicode characters, maximum length, and minimum length
- Each test method should have @DisplayName explaining what property is being validated
- Add assertion messages that explain WHY the input is valid or invalid
Validator class to test:
[PASTE YOUR VALIDATOR CLASS HERE]
Business rules to encode:
[DESCRIBE YOUR VALIDATION RULES HERE, e.g. "email must contain @, domain must have TLD of 2+ chars, max 254 chars"]
Prompt 3: Repository / DAO Tests with @DataJpaTest
When to use: You have a Spring Data JPA repository with custom query methods and want slice tests that run against a real in-memory or Testcontainers database.
Generate JUnit 6 @DataJpaTest slice tests for the following Spring Data JPA repository interface.
Requirements:
- Use @DataJpaTest (H2 in-memory by default)
- Use @Autowired TestEntityManager for test data setup (not the repository itself)
- Use @BeforeEach to insert fresh test data before each test
- Test every custom query method declared in the repository
- For each query method, test: result found, result not found, multiple results, edge case (empty DB)
- Use @DisplayName describing what the query should return under each condition
- Use assertThat (AssertJ) or assertEquals for list size verification
- Add @Tag("integration") to the class
Repository interface to test:
[PASTE YOUR REPOSITORY INTERFACE HERE]
Entity class:
[PASTE YOUR ENTITY CLASS HERE]
Prompt 4: REST Controller Tests with @WebMvcTest
When to use: You have a new REST controller and want fast, focused tests covering HTTP status codes, JSON response structure, and validation error responses.
Generate JUnit 6 @WebMvcTest tests for the following Spring MVC REST controller.
Requirements:
- Use @WebMvcTest([ControllerClass].class) and @MockBean for all service dependencies
- Inject MockMvc via @Autowired
- For each endpoint, test:
* 200/201 happy path with valid request body
* 400 Bad Request for invalid/missing fields
* 404 Not Found when resource does not exist
* Correct Content-Type header in response
- Use jsonPath() assertions to verify specific JSON fields
- Use @Nested classes to group tests per endpoint (e.g., "GET /api/resource/{id}")
- Use @DisplayName in English sentences on every test method
- Add @Tag("integration") on the class
Controller class to test:
[PASTE YOUR CONTROLLER CLASS HERE]
Request/Response DTOs:
[PASTE YOUR DTO CLASSES HERE]
Prompt 5: Exception Handling and Edge Case Coverage
When to use: You want to specifically ensure all exception paths and boundary conditions in a method are tested, including custom exception types.
Generate comprehensive JUnit 6 exception and edge case tests for the following method.
Requirements:
- Use assertThrows() for every exception path — NOT try/catch blocks
- After catching the exception, also assert on its getMessage() to verify it is descriptive
- Test every conditional branch that throws an exception
- Test boundary values: zero, negative numbers, Integer.MAX_VALUE, null, empty string, empty list
- Use @DisplayName that reads: "[method] throws [ExceptionType] when [condition]"
- Use assertDoesNotThrow() for valid inputs that must NOT throw
- Organise with @Nested: one inner class for exception tests, one for boundary tests
- Add comments in the test explaining WHY each boundary value is significant
Method signature and business rules:
[PASTE THE METHOD SIGNATURE AND JAVADOC HERE]
Custom exception classes (if any):
[PASTE EXCEPTION CLASSES HERE]
Prompt 6: Domain Object / Model Tests
When to use: You have a domain entity or value object with business logic (state transitions, computed properties, equality) that needs thorough testing.
Generate JUnit 6 tests for the following domain object / value object class.
Requirements:
- No Spring context needed — instantiate directly with new
- Test all state transition methods (e.g., order.confirm(), order.cancel())
- Test computed property methods (e.g., getTotalWithTax(), isEligibleForDiscount())
- Test equals() and hashCode() contract: two objects with same values must be equal
- Test that invalid state transitions throw the correct exception
- Use assertAll() to verify multiple properties of an object after a state change
- Use @Nested to organise: "Construction", "State Transitions", "Computed Properties"
- No mocks needed unless the class has dependencies
Domain class to test:
[PASTE YOUR DOMAIN CLASS HERE]
Business rules for state transitions:
[DESCRIBE VALID AND INVALID TRANSITIONS, e.g. "PENDING can go to CONFIRMED or CANCELLED but not SHIPPED"]
Prompt 7: Full Integration Test with @SpringBootTest
When to use: You want an end-to-end integration test that starts the full Spring context, exercises the real HTTP layer, and verifies data is persisted correctly.
Generate a JUnit 6 full integration test class using @SpringBootTest for the following feature.
Requirements:
- Use @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
- Use TestRestTemplate for HTTP calls
- Use @LocalServerPort to get the dynamic port
- Use @BeforeEach to clean up the database before each test
- Test the complete request-response cycle: HTTP request → service layer → database → HTTP response
- Use @Transactional where appropriate to ensure test isolation
- Verify: HTTP status code, response body structure, and that data was actually persisted
- Use @Nested to group by HTTP method (GET tests, POST tests, DELETE tests)
- Add @Tag("integration") on the class
- Add @DisplayName on the class and every test method
Feature to test end-to-end:
[DESCRIBE THE FEATURE, e.g. "User registration: POST /api/users creates a user, returns 201, persists email and hashed password"]
Entities involved:
[LIST THE ENTITIES AND THEIR RELATIONSHIPS]
Prompt 8: Mockito Interaction Verification Tests
When to use: Your service orchestrates multiple collaborators and you want tests that verify the correct interactions happen — not just the return value.
Generate JUnit 6 tests focused on Mockito interaction verification for the following service.
Requirements:
- Use @ExtendWith(MockitoExtension.class) with @Mock and @InjectMocks
- For each public method, write a test that verifies:
* Which mock methods were called (verify with times(n))
* Which mock methods were NOT called (verifyNoInteractions, verify with never())
* The exact arguments passed to each mock (use ArgumentCaptor for complex objects)
* The order of mock interactions when order matters (use InOrder)
- Use ArgumentCaptor to inspect the object passed to a void method
- Add assertions on the captured argument's fields (not just that it was called)
- Use @DisplayName: "[method] calls [dependency].[dependencyMethod] when [condition]"
- Add @DisplayName: "[method] does NOT call [dependency] when [invalidCondition]"
Service class to test:
[PASTE YOUR SERVICE CLASS HERE]
Dependencies (interfaces):
[PASTE DEPENDENCY INTERFACES HERE]
Business rule for interaction:
[e.g. "sendConfirmationEmail is called ONLY when order status changes to CONFIRMED, never on PENDING or CANCELLED"]
Prompt 9: @TestFactory Dynamic Tests from External Data
When to use: Your test cases are driven by data that lives in a file, database, or configuration — not known at compile time — and you want each case to appear as a named test.
Generate a JUnit 6 @TestFactory method that reads test cases from an external source.
Requirements:
- Use @TestFactory returning Stream
- Each DynamicTest should have a descriptive display name including the input values
- Read test data from: [CHOOSE ONE: a CSV file in src/test/resources / a List in a factory method / a JSON file]
- For each test case, verify: [DESCRIBE WHAT TO ASSERT]
- If any test case fails, the failure message must include: the input values, the expected output, and the actual output
- Organise complex test cases with DynamicContainer for grouping related cases
- The @TestFactory method itself should have @DisplayName
What is being tested:
[DESCRIBE THE METHOD/COMPONENT UNDER TEST]
Test data structure (columns/fields):
[DESCRIBE THE TEST DATA FORMAT, e.g. "CSV with columns: inputEmail, isValid, failureReason"]
Prompt 10: Complete Test Suite with All Patterns Combined
When to use: You want a gold-standard, comprehensive test class for a critical service that combines all JUnit 6 best practices in one file — suitable as a template or reference for your team.
Generate a gold-standard, comprehensive JUnit 6 test class for the following service.
This should serve as a reference template for our team's testing standards.
Requirements:
- @ExtendWith(MockitoExtension.class), @Mock, @InjectMocks
- @BeforeEach for fresh setup, @AfterEach for cleanup logging
- @Nested inner classes to organise by scenario:
* "Happy Path Tests" — all valid input scenarios
* "Validation and Exception Tests" — null, empty, invalid inputs
* "Boundary Value Tests" — edge cases at the limits of valid range
* "Interaction Tests" — Mockito verify() and ArgumentCaptor usage
- @ParameterizedTest with @CsvSource for data-driven cases
- @DisplayName on class and every method (full English sentence)
- assertAll() for multi-property object verification
- assertThrows() with exception message inspection
- Named constants instead of magic numbers
- Arrange-Act-Assert with blank line separators and section comments
- @Tag("unit") on every test method
- Test coverage target: every public method, every branch, every exception path
Service class to generate the gold-standard test for:
[PASTE YOUR COMPLETE SERVICE CLASS HERE]
Team naming convention preference:
[CHOOSE: shouldWhenPattern / givenWhenThen / displayNameOnly]
Tips for Getting Better Results from These Prompts
- Include Javadoc — paste the complete Javadoc for the method being tested. AI tools use it to understand intent and generate more accurate tests.
- Specify the framework versions — add “JUnit 6.0, Mockito 5.12, Spring Boot 3.3” to the prompt so the AI uses the correct API signatures.
- Show an example test — add “Follow the style of this existing test in our codebase: [paste one test method]” to enforce your team’s conventions.
- Iterate — start with Prompt 1 for the happy path, then run Prompt 5 specifically for exceptions. Specialised prompts produce better targeted tests than one giant prompt.
- Validate with mutation testing — after generating, run PIT (see Mutation Testing with PIT and JUnit 6) to verify that the generated tests would actually catch real bugs.
Frequently Asked Questions (FAQs)
Q1: Which AI tool produces the best JUnit 6 tests from these prompts?
All major LLMs (Claude, GPT-4o, Gemini 1.5 Pro) produce good results with these prompts. GitHub Copilot Chat excels at in-context generation because it can see your entire project. Claude tends to produce the most readable, well-structured test code with strong Arrange-Act-Assert separation. The most effective workflow is: Copilot for inline completion while typing, Claude/GPT-4 Chat for full class generation from the prompts above.
Q2: Should I use these prompts in an IDE plugin or a standalone chat?
Both work, but IDE plugins (Copilot, JetBrains AI) have the advantage of codebase context — they can see your existing tests, imports, and dependencies and generate more consistent, project-aware code. Standalone chat (Claude.ai, ChatGPT) allows longer prompts and more complex requirements but requires you to paste the full class. For complex service classes, standalone chat typically produces better results.
Q3: How do I prevent AI from generating tests that always pass?
Add this sentence to any prompt: “Every assertion must be a meaningful verification — assertNotNull alone is not sufficient. Each test must fail if the corresponding production code contains the bug it is designed to detect.” This instruction significantly improves assertion quality. After generation, run mutation testing to empirically verify that the tests catch bugs.
Q4: Can I use these prompts for Kotlin projects?
Yes, with minor modifications. Replace “use @ExtendWith(MockitoExtension.class)” with “use MockK library instead of Mockito” and add “generate Kotlin test code using idiomatic Kotlin syntax” to the prompt. JUnit 6 works identically in Kotlin projects — only the mocking library changes. MockK is the standard mocking library for Kotlin and integrates seamlessly with JUnit Jupiter.
Q5: How do I adapt these prompts for microservices that call external APIs?
Add to any integration test prompt: “Use WireMock to stub all external HTTP API calls. Start WireMock with @RegisterExtension WireMockExtension. Stub each external endpoint with the expected request/response pair before the test executes.” For full microservices testing patterns, see Testing Microservices with JUnit 6.
See Also
- JUnit 6 Tutorial: Complete Series Index
- Writing Your First Clean Test in JUnit 6 (Best Practices)
- AI-Powered Test Generation with JUnit 6 (Future of Testing)
- Mutation Testing with PIT and JUnit 6 (Improve Test Quality)
- Parameterized Tests in JUnit 6: All Sources Explained
Conclusion
These 10 prompts cover every major test scenario you will encounter when building a new Java project: unit tests, parameterised tests, repository tests, controller tests, exception tests, domain object tests, integration tests, interaction verification tests, dynamic tests, and gold-standard comprehensive templates. Copy them, fill in the placeholders with your actual code, and use the AI output as a strong first draft that you review and refine. The combination of AI speed and human judgement produces better tests, faster, than either approach alone.