Unit Testing এবং Dependency Injection (DI)
Unit Testing হল একটি সফটওয়্যার টেস্টিং প্রক্রিয়া, যার মাধ্যমে একক ইউনিট বা ফাংশনগুলির কার্যকারিতা পরীক্ষা করা হয়। Dependency Injection (DI) ব্যবহৃত হলে, Unit Testing আরও সহজ এবং কার্যকরী হয়, কারণ DI আপনাকে ডিপেনডেন্সি মক বা স্টাব করে টেস্ট করতে সহায়তা করে। Spring Framework-এ DI ব্যবহারের মাধ্যমে আপনি আপনার কোডের ডিপেনডেন্সি সহজেই ইনজেক্ট করতে পারেন এবং তারপর সেই ডিপেনডেন্সি মক (mock) বা স্টাব (stub) করতে পারেন Unit Testing এর সময়।
Spring এর সাথে Unit Testing করার জন্য JUnit এবং Mockito লাইব্রেরি খুব জনপ্রিয়। Mockito ব্যবহার করে আমরা সহজে মক অবজেক্ট তৈরি করতে পারি, যা DI করা Bean এর ডিপেনডেন্সি হিসেবে কাজ করবে।
Unit Testing এর জন্য DI ব্যবহারের প্রয়োজনীয়তা
- Loose Coupling: DI ব্যবহারের মাধ্যমে আপনার ক্লাসগুলির মধ্যে কমপ্লেক্স সম্পর্ক গড়ে ওঠে না, ফলে একক ইউনিট বা মেথড টেস্ট করা সহজ হয়।
- Mocking Dependencies: DI ব্যবহারের ফলে আপনি মক অবজেক্ট ব্যবহার করতে পারেন, যা আসল ডিপেনডেন্সির পরিবর্তে পরীক্ষিত কোডের জন্য একটি ভুয়া ইনপুট হিসেবে কাজ করবে।
- Testable Code: Spring DI কোডের টেস্টিং সহজ করে তোলে, কারণ DI এর মাধ্যমে কনস্ট্রাক্টরের মাধ্যমে ডিপেনডেন্সি ইনজেক্ট করা হয়, ফলে টেস্টিং করার জন্য মক অবজেক্ট প্রদান করা যায়।
Spring DI এর জন্য Unit Testing এর উদাহরণ
ধরা যাক, আমাদের একটি EmployeeService ক্লাস রয়েছে, যা EmployeeRepository নামে একটি ডিপেনডেন্সি গ্রহণ করছে। এখন, আমরা JUnit এবং Mockito ব্যবহার করে EmployeeService ক্লাসের টেস্ট করতে চাই, যেখানে EmployeeRepository মক করা হবে।
EmployeeService.java
public class EmployeeService {
private EmployeeRepository employeeRepository;
// Constructor Injection
public EmployeeService(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
public String getEmployeeNameById(int id) {
Employee employee = employeeRepository.findById(id);
if (employee != null) {
return employee.getName();
} else {
return "Employee not found";
}
}
}
EmployeeRepository.java
public interface EmployeeRepository {
Employee findById(int id);
}
Employee.java
public class Employee {
private int id;
private String name;
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
}
এখানে, EmployeeService ক্লাস EmployeeRepository থেকে ডেটা নিয়ে কাজ করছে। আমাদের টেস্টিং করার সময় EmployeeRepository কে মক করতে হবে, যাতে আসল ডাটাবেস কানেকশন না করতে হয়।
Unit Testing Using JUnit and Mockito
১. JUnit এবং Mockito Dependency Add করা (pom.xml)
<dependencies>
<!-- JUnit Dependency -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.1</version>
<scope>test</scope>
</dependency>
<!-- Mockito Dependency -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.9.0</version>
<scope>test</scope>
</dependency>
<!-- Mockito-JUnit integration -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>3.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>
২. EmployeeServiceTest.java
এখন, EmployeeService এর টেস্ট লিখতে, আমরা Mockito ব্যবহার করে EmployeeRepository এর মক অবজেক্ট তৈরি করব।
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.*;
public class EmployeeServiceTest {
@Mock
private EmployeeRepository employeeRepository;
private EmployeeService employeeService;
@BeforeEach
public void setUp() {
MockitoAnnotations.openMocks(this);
employeeService = new EmployeeService(employeeRepository);
}
@Test
public void testGetEmployeeNameById_Found() {
// Arrange: Mock the repository to return a specific employee
Employee mockEmployee = new Employee(1, "John Doe");
when(employeeRepository.findById(1)).thenReturn(mockEmployee);
// Act: Call the method to be tested
String result = employeeService.getEmployeeNameById(1);
// Assert: Verify the result
assertEquals("John Doe", result);
}
@Test
public void testGetEmployeeNameById_NotFound() {
// Arrange: Mock the repository to return null
when(employeeRepository.findById(1)).thenReturn(null);
// Act: Call the method to be tested
String result = employeeService.getEmployeeNameById(1);
// Assert: Verify the result
assertEquals("Employee not found", result);
}
}
ব্যাখ্যা:
- @Mock:
EmployeeRepositoryমক অবজেক্ট তৈরি করা হয়েছে, যাতে আমরা ডাটাবেসে সংযোগ না করে শুধু মক ডেটা ব্যবহার করতে পারি। - MockitoAnnotations.openMocks(this): এটি Mockito মক অবজেক্টগুলি ইনিশিয়ালাইজ করে।
- when(...).thenReturn(...): এই লাইনে, আমরা মক অবজেক্টে একটি নির্দিষ্ট রিটার্ন ভ্যালু সেট করেছি, যেমন
findById(1)কল করলে একটি নির্দিষ্টEmployeeঅবজেক্ট রিটার্ন হবে। - assertEquals(...): এটি পরীক্ষা করছে যে মেথডের আউটপুট আমাদের প্রত্যাশিত মানের সাথে মিলে কিনা।
Unit Testing এর জন্য DI ব্যবহারের সুবিধা
- ডিপেনডেন্সি সহজে মক করা যায়: Spring DI এর মাধ্যমে আপনি সহজেই মক অবজেক্ট তৈরি করতে পারেন, যা ইউনিট টেস্টিং এর জন্য অত্যন্ত কার্যকরী।
- Loose Coupling: DI ব্যবহারের মাধ্যমে আপনার কোডের মধ্যে ঢিলেঢালা সম্পর্ক তৈরি হয়, যা টেস্টিং এবং রক্ষণাবেক্ষণকে সহজ করে তোলে।
- Testability: Spring DI ব্যবহারের মাধ্যমে কোডটি আরও টেস্টেবল হয়ে ওঠে, কারণ ডিপেনডেন্সিগুলি সহজেই ইনজেক্ট করা এবং মক করা যায়।
- Independence: আপনি যখন ডিপেনডেন্সি মক করেন, তখন আপনার টেস্টগুলো পুরোপুরি নির্ভর করে না আসল ডিপেনডেন্সির উপর, যেমন ডাটাবেস বা API কল, ফলে দ্রুত এবং নির্ভরযোগ্য টেস্টিং সম্ভব হয়।
সারাংশ
Spring Dependency Injection (DI) ব্যবহার করে Unit Testing করা সহজ হয়ে যায়, কারণ DI এর মাধ্যমে আপনি সহজে মক অবজেক্ট তৈরি করতে পারেন এবং টেস্ট করতে পারেন। JUnit এবং Mockito এর মাধ্যমে Spring Beans এবং তাদের ডিপেনডেন্সি মক করা এবং টেস্ট করা সম্ভব। DI ব্যবহারের ফলে কোডের টেস্টিং সহজ এবং কার্যকরী হয়ে ওঠে, কারণ ডিপেনডেন্সিগুলিকে এক জায়গায় কনফিগার করা হয় এবং মক করা যায়।
Read more