|
| 1 | +# Testing Guide for Hommr |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +This project includes a comprehensive test suite with over 2,000 lines of test code covering all major components of the Hommr plugin. |
| 6 | + |
| 7 | +## Quick Start |
| 8 | + |
| 9 | +### Running All Tests |
| 10 | + |
| 11 | +```bash |
| 12 | +./gradlew test |
| 13 | +``` |
| 14 | + |
| 15 | +### Running Tests with Detailed Output |
| 16 | + |
| 17 | +```bash |
| 18 | +./gradlew test --info |
| 19 | +``` |
| 20 | + |
| 21 | +### Running Specific Test Classes |
| 22 | + |
| 23 | +```bash |
| 24 | +# Run tests for Home model |
| 25 | +./gradlew test --tests HomeTest |
| 26 | + |
| 27 | +# Run tests for PlayerHomes model |
| 28 | +./gradlew test --tests PlayerHomesTest |
| 29 | + |
| 30 | +# Run tests for DatabaseManager |
| 31 | +./gradlew test --tests DatabaseManagerTest |
| 32 | + |
| 33 | +# Run tests for HomeManager |
| 34 | +./gradlew test --tests HomeManagerTest |
| 35 | + |
| 36 | +# Run tests for Hommr plugin class |
| 37 | +./gradlew test --tests HommrTest |
| 38 | +``` |
| 39 | + |
| 40 | +### Running Tests for Specific Methods |
| 41 | + |
| 42 | +```bash |
| 43 | +# Run a single test method |
| 44 | +./gradlew test --tests HomeTest.testFromLocationCreatesHomeWithCorrectData |
| 45 | + |
| 46 | +# Run tests matching a pattern |
| 47 | +./gradlew test --tests HomeTest.*Location* |
| 48 | +``` |
| 49 | + |
| 50 | +## Test Structure |
| 51 | + |
| 52 | +``` |
| 53 | +src/test/java/me/axeno/hommr/ |
| 54 | +├── HommrTest.java # Main plugin lifecycle tests |
| 55 | +├── managers/ |
| 56 | +│ ├── DatabaseManagerTest.java # Database operations tests |
| 57 | +│ └── HomeManagerTest.java # Home management logic tests |
| 58 | +└── models/ |
| 59 | + ├── HomeTest.java # Home model tests |
| 60 | + └── PlayerHomesTest.java # Player homes collection tests |
| 61 | +``` |
| 62 | + |
| 63 | +## Test Coverage |
| 64 | + |
| 65 | +- **HomeTest**: 22 tests covering location conversion, data persistence, and edge cases |
| 66 | +- **PlayerHomesTest**: 30 tests covering home collections, thread safety, and case sensitivity |
| 67 | +- **DatabaseManagerTest**: 28 tests covering database operations, persistence, and integrity |
| 68 | +- **HomeManagerTest**: 30+ tests covering business logic, events, and player interactions |
| 69 | +- **HommrTest**: 35+ tests covering plugin lifecycle and component initialization |
| 70 | + |
| 71 | +**Total**: 145+ comprehensive test cases |
| 72 | + |
| 73 | +## Requirements |
| 74 | + |
| 75 | +- **Java**: 21 or higher |
| 76 | +- **Gradle**: 8.x (included via wrapper) |
| 77 | + |
| 78 | +## Test Dependencies |
| 79 | + |
| 80 | +The test suite uses: |
| 81 | +- **JUnit 5** (Jupiter 5.10.1) - Modern testing framework |
| 82 | +- **Mockito 5** (5.8.0) - Mocking framework for dependencies |
| 83 | +- **Paper API** - For Bukkit/Spigot testing |
| 84 | +- **ORMLite** - For database testing |
| 85 | +- **SQLite JDBC** - For in-memory database tests |
| 86 | + |
| 87 | +## Continuous Integration |
| 88 | + |
| 89 | +Tests are automatically run in CI/CD via GitHub Actions on: |
| 90 | +- Pull requests |
| 91 | +- Pushes to main branches |
| 92 | + |
| 93 | +See `.github/workflows/build.yml` for CI configuration. |
| 94 | + |
| 95 | +## Test Patterns |
| 96 | + |
| 97 | +### Mocking Bukkit Objects |
| 98 | + |
| 99 | +```java |
| 100 | +@Mock |
| 101 | +private World mockWorld; |
| 102 | + |
| 103 | +@Mock |
| 104 | +private Player mockPlayer; |
| 105 | + |
| 106 | +@BeforeEach |
| 107 | +void setUp() { |
| 108 | + when(mockWorld.getName()).thenReturn("world"); |
| 109 | + when(mockPlayer.getUniqueId()).thenReturn(testPlayerId); |
| 110 | +} |
| 111 | +``` |
| 112 | + |
| 113 | +### Testing Events |
| 114 | + |
| 115 | +```java |
| 116 | +ArgumentCaptor<HomeSetEvent> eventCaptor = ArgumentCaptor.forClass(HomeSetEvent.class); |
| 117 | +HomeManager.setHome(mockPlayer, "home1", location); |
| 118 | +verify(mockPluginManager).callEvent(eventCaptor.capture()); |
| 119 | +HomeSetEvent event = eventCaptor.getValue(); |
| 120 | +assertEquals("home1", event.getHomeName()); |
| 121 | +``` |
| 122 | + |
| 123 | +### Testing Database Operations |
| 124 | + |
| 125 | +```java |
| 126 | +@TempDir |
| 127 | +Path tempDir; |
| 128 | + |
| 129 | +@BeforeEach |
| 130 | +void setUp() { |
| 131 | + when(mockPlugin.getDataFolder()).thenReturn(tempDir.toFile()); |
| 132 | + databaseManager.init(); |
| 133 | +} |
| 134 | +``` |
| 135 | + |
| 136 | +## Writing New Tests |
| 137 | + |
| 138 | +### Best Practices |
| 139 | + |
| 140 | +1. **Test Naming**: Use descriptive names that explain what is being tested |
| 141 | + - ✅ `testSetHomeCreatesNewHome()` |
| 142 | + - ❌ `testSetHome1()` |
| 143 | + |
| 144 | +2. **Arrange-Act-Assert**: Structure tests clearly |
| 145 | + ```java |
| 146 | + @Test |
| 147 | + void testSetHomeCreatesNewHome() { |
| 148 | + // Arrange |
| 149 | + Location location = new Location(mockWorld, 100, 64, 200); |
| 150 | + |
| 151 | + // Act |
| 152 | + boolean result = HomeManager.setHome(mockPlayer, "home1", location); |
| 153 | + |
| 154 | + // Assert |
| 155 | + assertTrue(result); |
| 156 | + assertTrue(HomeManager.hasHome(testPlayerId, "home1")); |
| 157 | + } |
| 158 | + ``` |
| 159 | + |
| 160 | +3. **Test Isolation**: Each test should be independent |
| 161 | + - Use `@BeforeEach` for setup |
| 162 | + - Use `@AfterEach` for cleanup |
| 163 | + - Don't rely on test execution order |
| 164 | + |
| 165 | +4. **Edge Cases**: Always test boundary conditions |
| 166 | + - Null values |
| 167 | + - Empty collections |
| 168 | + - Maximum/minimum values |
| 169 | + - Special characters |
| 170 | + |
| 171 | +5. **Mock Cleanup**: Close static mocks in `@AfterEach` |
| 172 | + ```java |
| 173 | + @AfterEach |
| 174 | + void tearDown() { |
| 175 | + if (bukkitMockedStatic != null) { |
| 176 | + bukkitMockedStatic.close(); |
| 177 | + } |
| 178 | + } |
| 179 | + ``` |
| 180 | + |
| 181 | +## Debugging Tests |
| 182 | + |
| 183 | +### Enable Debug Logging |
| 184 | + |
| 185 | +```bash |
| 186 | +./gradlew test --debug |
| 187 | +``` |
| 188 | + |
| 189 | +### Show Standard Output |
| 190 | + |
| 191 | +Edit `build.gradle`: |
| 192 | +```gradle |
| 193 | +test { |
| 194 | + testLogging { |
| 195 | + showStandardStreams = true |
| 196 | + } |
| 197 | +} |
| 198 | +``` |
| 199 | + |
| 200 | +### Run Tests in IDE |
| 201 | + |
| 202 | +Most IDEs (IntelliJ IDEA, Eclipse, VS Code) can run JUnit 5 tests directly: |
| 203 | +1. Right-click on test class or method |
| 204 | +2. Select "Run Test" or "Debug Test" |
| 205 | + |
| 206 | +## Common Issues |
| 207 | + |
| 208 | +### Test Failures |
| 209 | + |
| 210 | +1. **Mockito Issues**: Ensure all mocks are properly initialized with `@ExtendWith(MockitoExtension.class)` |
| 211 | +2. **Static Mocks**: Always close `MockedStatic` instances in `@AfterEach` |
| 212 | +3. **Bukkit API**: Use mocks for all Bukkit classes (Server, World, Player, etc.) |
| 213 | + |
| 214 | +### Build Issues |
| 215 | + |
| 216 | +1. **Java Version**: Ensure Java 21 is installed |
| 217 | + ```bash |
| 218 | + java -version |
| 219 | + ``` |
| 220 | + |
| 221 | +2. **Gradle Sync**: Refresh Gradle dependencies |
| 222 | + ```bash |
| 223 | + ./gradlew --refresh-dependencies |
| 224 | + ``` |
| 225 | + |
| 226 | +## Performance |
| 227 | + |
| 228 | +Tests are designed to run quickly: |
| 229 | +- **Unit Tests**: < 1 second per test |
| 230 | +- **Database Tests**: Use in-memory SQLite for speed |
| 231 | +- **Full Suite**: Typically completes in < 30 seconds |
| 232 | + |
| 233 | +## Coverage Reports |
| 234 | + |
| 235 | +To generate code coverage reports (requires JaCoCo plugin): |
| 236 | + |
| 237 | +```bash |
| 238 | +./gradlew test jacocoTestReport |
| 239 | +``` |
| 240 | + |
| 241 | +Report will be available at: `build/reports/jacoco/test/html/index.html` |
| 242 | + |
| 243 | +## Contributing Tests |
| 244 | + |
| 245 | +When adding new features: |
| 246 | +1. Write tests first (TDD approach) or alongside the implementation |
| 247 | +2. Ensure at least 80% code coverage for new code |
| 248 | +3. Include both positive and negative test cases |
| 249 | +4. Test edge cases and boundary conditions |
| 250 | +5. Update this documentation if adding new test patterns |
| 251 | + |
| 252 | +## Additional Resources |
| 253 | + |
| 254 | +- [JUnit 5 User Guide](https://junit.org/junit5/docs/current/user-guide/) |
| 255 | +- [Mockito Documentation](https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html) |
| 256 | +- [Paper API Documentation](https://jd.papermc.io/paper/1.21/) |
| 257 | + |
| 258 | +For detailed test information, see `src/test/TEST_SUMMARY.md`. |
0 commit comments