Integration testing
Spring Boot অ্যাপ্লিকেশন ডেভেলপ করার সময় আমরা সাধারণত দুটি ধরণের টেস্ট লিখি — Unit Test এবং Integration Test।
Unit Test আলাদা আলাদা ক্লাস বা মেথড যাচাই করে, কিন্তু Integration Test পুরো সিস্টেমের বিভিন্ন অংশ একসাথে ঠিকভাবে কাজ করছে কিনা তা যাচাই করে।
Integration Test কী?
Integration Test হলো এমন একটি টেস্ট যেখানে Spring ApplicationContext পুরোপুরি লোড হয়,
এবং Repository, Service, Controller ইত্যাদি একসাথে কাজ করে কিনা তা যাচাই করা হয়।
উদাহরণ:
“UserController → UserService → UserRepository” চেইন একসাথে সঠিকভাবে কাজ করছে কিনা,
সেটি যাচাই করতে Integration Test ব্যবহার করা হয়।
প্রয়োজনীয় Dependency
Spring Boot এ Integration Testing সহজ করতে নিচের dependency গুলো ব্যবহার হয়:
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
এখানে spring-boot-starter-test প্যাকেজের মধ্যে JUnit, Mockito, AssertJ, Hamcrest, Spring Test Context ইত্যাদি সব কিছুই আগে থেকেই অন্তর্ভুক্ত থাকে।
একটি সাধারণ Integration Test এর উদাহরণ
ধরা যাক আমাদের একটি UserController আছে, যা ডাটাবেস থেকে ইউজার লিস্ট রিটার্ন করে।
Entity
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// getter, setter
}
Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
Service
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public List<User> getAllUsers() {
return userRepository.findAll();
}
}
Controller
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public List<User> getUsers() {
return userService.getAllUsers();
}
}
Integration Test লিখি
@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private UserRepository userRepository;
@BeforeEach
void setUp() {
userRepository.deleteAll();
userRepository.save(new User(null, "Maruf"));
userRepository.save(new User(null, "Rihan"));
}
@Test
void shouldReturnAllUsers() throws Exception {
mockMvc.perform(get("/api/users"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.length()").value(2))
.andExpect(jsonPath("$[0].name").value("Maruf"));
}
}
এখানে কী হচ্ছে
| Annotation | কাজ |
|---|---|
@SpringBootTest |
পুরো Spring Context লোড করে (Controller, Service, Repository সব সহ)। |
@AutoConfigureMockMvc |
MockMvc কনফিগার করে যাতে আমরা HTTP রিকোয়েস্ট simulate করতে পারি। |
@BeforeEach |
প্রতিটি টেস্টের আগে ডাটাবেজ initialize করে। |
mockMvc.perform(...) |
API কল simulate করে যেমন /api/users। |
Database নিয়ে Integration Test
Integration Test সাধারণত in-memory ডাটাবেজ যেমন H2 ব্যবহার করে।
# src/test/resources/application.yml
spring:
datasource:
url: jdbc:h2:mem:testdb
driverClassName: org.h2.Driver
username: sa
password:
jpa:
hibernate:
ddl-auto: create-drop
এতে করে টেস্টের সময় একটা অস্থায়ী ডাটাবেজ তৈরি হয় এবং প্রতিটি টেস্ট শেষে ডিলিট হয়ে যায়।
REST API Integration Test (JSON সহ)
@Test
void shouldCreateNewUser() throws Exception {
String newUser = "{\"name\": \"Niham\"}";
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(newUser))
.andExpect(status().isOk());
assertEquals(3, userRepository.count());
}
Transactional Test
যদি প্রতিটি টেস্ট শেষে ডাটাবেজে করা পরিবর্তন rollback করতে চাও,
তাহলে @Transactional annotation ব্যবহার করো:
@SpringBootTest
@Transactional
public class UserRepositoryTest {
@Autowired
private UserRepository repo;
@Test
void testSaveUser() {
repo.save(new User(null, "TestUser"));
assertEquals(1, repo.count());
}
}
এখানে প্রতিটি টেস্ট শেষে Spring স্বয়ংক্রিয়ভাবে transaction rollback করবে।
Test Slicing (Controller / Repository আলাদা করে টেস্ট করা)
Spring Boot কিছু smart test slice annotations দিয়েছে:
| Annotation | কাজ |
|---|---|
@WebMvcTest |
শুধু Controller layer টেস্ট করে (Service/Repository লোড হয় না)। |
@DataJpaTest |
শুধুমাত্র Repository layer টেস্ট করে (H2 database সহ)। |
@JsonTest |
JSON serialization/deserialization টেস্ট করে। |
উদাহরণ:
@DataJpaTest
class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@Test
void saveAndFindUser() {
userRepository.save(new User(null, "Arni"));
Optional<User> user = userRepository.findById(1L);
assertTrue(user.isPresent());
}
}