JUnit এবং Mockito এর মাধ্যমে Multithreaded Code Test করা

Testing এবং Debugging Concurrency - জাভা কনকারেন্সি (Java Concurrency) - Java Technologies

360

মাল্টিথ্রেডেড কোড টেস্ট করা চ্যালেঞ্জিং কারণ এটি থ্রেড ইন্টারঅ্যাকশন এবং কনকারেন্সি সমস্যা যেমন Deadlock, Race Condition, এবং Thread-Safety নিশ্চিত করতে হয়। JUnit এবং Mockito একত্রে ব্যবহার করে মাল্টিথ্রেডেড কোড সহজেই টেস্ট করা সম্ভব।


JUnit এবং Mockito কেন?

  1. JUnit: ইউনিট টেস্টিং ফ্রেমওয়ার্ক, যা সিঙ্ক্রোনাস এবং অ্যাসিঙ্ক্রোনাস কোড টেস্ট করার জন্য ব্যবহৃত হয়।
  2. Mockito: মক (Mock) অবজেক্ট তৈরি করে নির্দিষ্ট বিহেভিয়ার যাচাই করার জন্য।

টেস্টিং এর ক্ষেত্রে চ্যালেঞ্জ

  1. Concurrency Issues: মাল্টিথ্রেডেড কোডে Race Conditions, Deadlock, এবং Data Corruption টেস্ট করা।
  2. Thread-Safety Validation: শেয়ারড রিসোর্স ঠিকমতো কাজ করছে কিনা নিশ্চিত করা।
  3. Time-Sensitive Operations: থ্রেডের টাস্ক সময়মতো শেষ হচ্ছে কিনা তা যাচাই করা।

JUnit এবং Mockito দিয়ে Multithreaded Code Test করার উদাহরণ

১. Thread-Safe Counter Test

একটি Counter ক্লাস টেস্ট করা যেটি থ্রেড-সেফ।

Counter Class:

public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

JUnit টেস্ট:

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class CounterTest {
    @Test
    public void testCounterWithMultipleThreads() throws InterruptedException {
        Counter counter = new Counter();

        Runnable task = counter::increment;

        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        assertEquals(2, counter.getCount());
    }
}

২. Race Condition Test

একটি কোডে Race Condition রয়েছে কিনা তা টেস্ট করা।

Unsynchronized Counter:

public class UnsafeCounter {
    private int count = 0;

    public void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

JUnit টেস্ট:

import org.junit.jupiter.api.Test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static org.junit.jupiter.api.Assertions.assertNotEquals;

public class UnsafeCounterTest {
    @Test
    public void testRaceCondition() throws InterruptedException {
        UnsafeCounter counter = new UnsafeCounter();
        ExecutorService executor = Executors.newFixedThreadPool(10);

        for (int i = 0; i < 1000; i++) {
            executor.submit(counter::increment);
        }

        executor.shutdown();
        Thread.sleep(100); // অপেক্ষা করুন সব টাস্ক শেষ হওয়া পর্যন্ত

        // Race Condition এর কারণে ফলাফল অপ্রত্যাশিত হতে পারে
        assertNotEquals(1000, counter.getCount());
    }
}

৩. Mockito দিয়ে Thread Interaction Verify করা

Service Class:

public class MyService {
    public void performTask() {
        System.out.println("Task performed by " + Thread.currentThread().getName());
    }
}

Test Class:

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

public class MyServiceTest {
    @Test
    public void testPerformTaskWithMockito() throws InterruptedException {
        MyService myService = Mockito.mock(MyService.class);
        ExecutorService executor = Executors.newFixedThreadPool(3);

        for (int i = 0; i < 5; i++) {
            executor.submit(myService::performTask);
        }

        executor.shutdown();
        Thread.sleep(100); // অপেক্ষা করুন টাস্ক শেষ হওয়া পর্যন্ত

        // Verify that performTask was called 5 times
        verify(myService, times(5)).performTask();
    }
}

৪. CompletableFuture টেস্ট করা

CompletableFuture Example:

import java.util.concurrent.CompletableFuture;

public class AsyncService {
    public CompletableFuture<String> fetchData() {
        return CompletableFuture.supplyAsync(() -> "Data");
    }
}

JUnit টেস্ট:

import org.junit.jupiter.api.Test;

import java.util.concurrent.ExecutionException;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class AsyncServiceTest {
    @Test
    public void testFetchData() throws ExecutionException, InterruptedException {
        AsyncService service = new AsyncService();
        CompletableFuture<String> future = service.fetchData();

        // Wait for the result and validate
        assertEquals("Data", future.get());
    }
}

কৌশল ও টিপস

  1. Thread Synchronization টেস্ট: join() বা ExecutorService.shutdown() ব্যবহার করে থ্রেড শেষ হওয়া নিশ্চিত করুন।
  2. Mockito দিয়ে মক তৈরি: মাল্টিথ্রেডেড পরিবেশে নির্দিষ্ট পদ্ধতির কল নিশ্চিত করতে Mockito.verify() ব্যবহার করুন।
  3. Awaitility ব্যবহার: অ্যাসিঙ্ক্রোনাস অপারেশন টেস্ট করার জন্য Awaitility লাইব্রেরি ব্যবহার করতে পারেন।
  4. Timeout ব্যবহার: নির্দিষ্ট সময়ের মধ্যে টাস্ক শেষ হয়েছে কিনা যাচাই করতে Thread.sleep() বা await() ব্যবহার করুন।

JUnit এবং Mockito দিয়ে Multithreaded টেস্টের সুবিধা

  1. Concurrency Issues ধরা: Race Condition এবং Deadlock চিহ্নিত করতে সহজ।
  2. অ্যাসিঙ্ক্রোনাস টাস্ক টেস্ট: CompletableFuture বা কলব্যাক মেকানিজম সহজেই টেস্ট করা যায়।
  3. কোড কভারেজ বৃদ্ধি: সমস্ত পাথ কভার করার মাধ্যমে কোড আরও নির্ভরযোগ্য হয়।

JUnit এবং Mockito ব্যবহার করে মাল্টিথ্রেডেড কোড টেস্ট করা কার্যকর এবং সহজ। এটি ডেডলক, রেস কন্ডিশন এবং থ্রেড-সেফটি ইস্যু সনাক্ত করতে সাহায্য করে। সঠিকভাবে টেস্ট কাঠামো সেটআপ করলে মাল্টিথ্রেডেড অ্যাপ্লিকেশন উন্নত এবং নির্ভরযোগ্য হয়।

Content added By
Promotion

Are you sure to start over?

Loading...