

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
12345# Java Testing67> This file extends [common/testing.md](../common/testing.md) with Java-specific content.89## Test Framework1011- **JUnit 5** (`@Test`, `@ParameterizedTest`, `@Nested`, `@DisplayName`)12- **AssertJ** for fluent assertions (`assertThat(result).isEqualTo(expected)`)13- **Mockito** for mocking dependencies14- **Testcontainers** for integration tests requiring databases or services1516## Test Organization1718```19src/test/java/com/example/app/20 service/ # Unit tests for service layer21 controller/ # Web layer / API tests22 repository/ # Data access tests23 integration/ # Cross-layer integration tests24```2526Mirror the `src/main/java` package structure in `src/test/java`.2728## Unit Test Pattern2930```java31@ExtendWith(MockitoExtension.class)32class OrderServiceTest {3334 @Mock35 private OrderRepository orderRepository;3637 private OrderService orderService;3839 @BeforeEach40 void setUp() {41 orderService = new OrderService(orderRepository);42 }4344 @Test45 @DisplayName("findById returns order when exists")46 void findById_existingOrder_returnsOrder() {47 var order = new Order(1L, "Alice", BigDecimal.TEN);48 when(orderRepository.findById(1L)).thenReturn(Optional.of(order));4950 var result = orderService.findById(1L);5152 assertThat(result.customerName()).isEqualTo("Alice");53 verify(orderRepository).findById(1L);54 }5556 @Test57 @DisplayName("findById throws when order not found")58 void findById_missingOrder_throws() {59 when(orderRepository.findById(99L)).thenReturn(Optional.empty());6061 assertThatThrownBy(() -> orderService.findById(99L))62 .isInstanceOf(OrderNotFoundException.class)63 .hasMessageContaining("99");64 }65}66```6768## Parameterized Tests6970```java71@ParameterizedTest72@CsvSource({73 "100.00, 10, 90.00",74 "50.00, 0, 50.00",75 "200.00, 25, 150.00"76})77@DisplayName("discount applied correctly")78void applyDiscount(BigDecimal price, int pct, BigDecimal expected) {79 assertThat(PricingUtils.discount(price, pct)).isEqualByComparingTo(expected);80}81```8283## Integration Tests8485Use Testcontainers for real database integration:8687```java88@Testcontainers89class OrderRepositoryIT {9091 @Container92 static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16");9394 private OrderRepository repository;9596 @BeforeEach97 void setUp() {98 var dataSource = new PGSimpleDataSource();99 dataSource.setUrl(postgres.getJdbcUrl());100 dataSource.setUser(postgres.getUsername());101 dataSource.setPassword(postgres.getPassword());102 repository = new JdbcOrderRepository(dataSource);103 }104105 @Test106 void save_and_findById() {107 var saved = repository.save(new Order(null, "Bob", BigDecimal.ONE));108 var found = repository.findById(saved.getId());109 assertThat(found).isPresent();110 }111}112```113114For Spring Boot integration tests, see skill: `springboot-tdd`.115116## Test Naming117118Use descriptive names with `@DisplayName`:119- `methodName_scenario_expectedBehavior()` for method names120- `@DisplayName("human-readable description")` for reports121122## Coverage123124- Target 80%+ line coverage125- Use JaCoCo for coverage reporting126- Focus on service and domain logic — skip trivial getters/config classes127128## References129130See skill: `springboot-tdd` for Spring Boot TDD patterns with MockMvc and Testcontainers.131See skill: `java-coding-standards` for testing expectations.132
One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| ThanhTrunggDEV/DontBeLazy.cursor/rules/zh-agents.mdc · 6 | Cursor rules | no sections | 50/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/zh-patterns.mdc · 6 | Cursor rules | api | 30/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.agent/AGENTS.md · 6 | AGENTS.md | buildteststylearch+4 | 77/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/AGENTS.md · 6 | AGENTS.md | buildteststylearch+4 | 77/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/common-agents.mdc · 6 | Cursor rules | agent-behaviour | 50/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/common-code-review.mdc · 6 | Cursor rules | styletesting-strategygitsecurity+3 | 65/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/common-coding-style.mdc · 6 | Cursor rules | style | 54/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/common-development-workflow.mdc · 6 | Cursor rules | gitagent-behaviour | 39/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/common-git-workflow.mdc · 6 | Cursor rules | lint-formatgitagent-behaviour | 43/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/common-hooks.mdc · 6 | Cursor rules | styletypessecuritydo-not | 36/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/common-patterns.mdc · 6 | Cursor rules | lint-formatstyleapi | 52/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/common-performance.mdc · 6 | Cursor rules | buildperformance | 48/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/common-security.mdc · 6 | Cursor rules | security | 39/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/common-testing.mdc · 6 | Cursor rules | testtesting-strategyagent-behaviour | 34/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/cpp-coding-style.mdc · 6 | Cursor rules | lint-formatstyle | 52/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/cpp-hooks.mdc · 6 | Cursor rules | buildlint-formatdeployment | 60/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/cpp-patterns.mdc · 6 | Cursor rules | style | 54/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/cpp-security.mdc · 6 | Cursor rules | securityperformancedo-not | 73/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/cpp-testing.mdc · 6 | Cursor rules | testtesting-strategy | 55/100 | 14 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/csharp-coding-style.mdc · 6 | Cursor rules | lint-formatstyletypes | 66/100 | 14 days ago |
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| hiromaily/go-crypto-wallet.cursor/rules/typescript.mdc · 126 | Cursor rules | setupbuildtestlint-format+6 | 100/100 | 14 days ago | |
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 45 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 14 days ago | |
| dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| markstev/mark-starter.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+6 | 99/100 | 14 days ago | |
| Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 14 days ago | |
| TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 45 | Cursor rules | teststyletesting-strategysecurity+3 | 97/100 | 14 days ago |
A badge carrying the measured quality of the strongest agent config file in this repository, out of 100. It reads from this index every time somebody loads your page, so it changes when the measurement changes and there is nothing to keep up to date. Free, no account, and the value is not something you or we can set by hand.
[](https://rulestack.kynth.studio/configs/thanhtrunggdev-dontbelazy-cursor-rules-java-testing)Would rather not hotlink us? Every badge is also served in shields.io’s endpoint schema, so shields renders the image and your readers never talk to our domain:
Published by Toolproof, the masthead over this index and eight others. The method behind the number is at toolproof.kynth.studio/methodology, and the whole thing is readable as JSON with no key at /api.