Integration Testing with @SpringBootTest
Unit tests check logic in isolation. But what if the JPA query you wrote is actually invalid SQL? A mock won't catch that. Integration tests start the real Spring Boot application to ensure all pieces (Controllers, Services, Repositories, and Database) fit together perfectly.
The Ramoji Film City Set Walkthrough Analogy:
Unit testing is like testing a single fake sword in a prop room to see if it bends correctly.
Integration testing is bringing 500 actors onto the set, turning on the cameras, and shooting a scene. You are testing if the lighting, the cameras, the actors, and the set all work together.
@SpringBootTest boots up the entire Spring Application Context. It connects to a real database (usually an H2 in-memory database for tests) and runs actual SQL queries.
- @SpringBootTest: Tells Spring Boot to start the full application context for this test.
- @AutoConfigureTestDatabase: Replaces your MySQL/PostgreSQL config with a fast, in-memory H2 database automatically, so you don't mess up your real data.
- @Transactional: If you add this to a test, any data inserted during the test is rolled back at the end, keeping your test database clean.
package com.devinhyderabad;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
// 1. Start the full Spring Boot context
@SpringBootTest
// 2. Use an in-memory H2 database instead of real MySQL
@AutoConfigureTestDatabase
// 3. Rollback DB changes after the test finishes
@Transactional
public class BookRepositoryIntegrationTest {
@Autowired
private BookRepository bookRepository;
@Test
public void testFindByAuthor_ReturnsCorrectBooks() {
// 1. Arrange: Insert real data into the H2 database
bookRepository.save(new Book(1L, "Spring Guide", "Deva"));
bookRepository.save(new Book(2L, "Angular Guide", "Deva"));
bookRepository.save(new Book(3L, "Java Basics", "Sai"));
// 2. Act: Call the real Spring Data JPA method (Real SQL is generated!)
List<Book> devaBooks = bookRepository.findByAuthor("Deva");
// 3. Assert: Check the result
assertEquals(2, devaBooks.size());
}
}Interview Question: "Why should you use @Transactional on integration tests in Spring Boot?"
Answer: By default, if a test method inserts data into the database, that data stays there after the test finishes. This can cause subsequent tests to fail because the database state is dirty. Adding @Transactional to the test class makes Spring automatically roll back the transaction at the end of each test method, ensuring a clean state for the next test.
Enterprise Note: For testing real database constraints (like unique keys), @DataJpaTest is often preferred over @SpringBootTest because it only boots the JPA layer, making it much faster. But for testing the full flow from Controller to DB, @SpringBootTest is required.
Key Takeaways
- ✅ @SpringBootTest starts the full application context for integration testing
- ✅ @AutoConfigureTestDatabase replaces real DB with fast H2 in-memory DB
- ✅ @Transactional on tests rolls back data automatically after each test
- ✅ @DataJpaTest is a faster alternative for testing only the JPA/repository layer
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login