Added tests for singleton pattern
This commit is contained in:
		| @@ -0,0 +1,17 @@ | ||||
| package com.iluwatar.singleton; | ||||
|  | ||||
| /** | ||||
|  * Date: 12/29/15 - 19:20 PM | ||||
|  * | ||||
|  * @author Jeroen Meulemeester | ||||
|  */ | ||||
| public class EnumIvoryTowerTest extends SingletonTest<EnumIvoryTower> { | ||||
|  | ||||
|   /** | ||||
|    * Create a new singleton test instance using the given 'getInstance' method | ||||
|    */ | ||||
|   public EnumIvoryTowerTest() { | ||||
|     super(() -> EnumIvoryTower.INSTANCE); | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,17 @@ | ||||
| package com.iluwatar.singleton; | ||||
|  | ||||
| /** | ||||
|  * Date: 12/29/15 - 19:22 PM | ||||
|  * | ||||
|  * @author Jeroen Meulemeester | ||||
|  */ | ||||
| public class InitializingOnDemandHolderIdiomTest extends SingletonTest<InitializingOnDemandHolderIdiom> { | ||||
|  | ||||
|   /** | ||||
|    * Create a new singleton test instance using the given 'getInstance' method | ||||
|    */ | ||||
|   public InitializingOnDemandHolderIdiomTest() { | ||||
|     super(InitializingOnDemandHolderIdiom::getInstance); | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,17 @@ | ||||
| package com.iluwatar.singleton; | ||||
|  | ||||
| /** | ||||
|  * Date: 12/29/15 - 19:23 PM | ||||
|  * | ||||
|  * @author Jeroen Meulemeester | ||||
|  */ | ||||
| public class IvoryTowerTest extends SingletonTest<IvoryTower> { | ||||
|  | ||||
|   /** | ||||
|    * Create a new singleton test instance using the given 'getInstance' method | ||||
|    */ | ||||
|   public IvoryTowerTest() { | ||||
|     super(IvoryTower::getInstance); | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -1,90 +0,0 @@ | ||||
| package com.iluwatar.singleton; | ||||
|  | ||||
| import static org.junit.Assert.assertEquals; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| import java.util.concurrent.Callable; | ||||
| import java.util.concurrent.ExecutionException; | ||||
| import java.util.concurrent.ExecutorService; | ||||
| import java.util.concurrent.Executors; | ||||
| import java.util.concurrent.Future; | ||||
|  | ||||
| import org.junit.Test; | ||||
|  | ||||
| /** | ||||
|  * This class provides several test case that test singleton construction. | ||||
|  * | ||||
|  * The first proves that multiple calls to the singleton getInstance object are the same when called | ||||
|  * in the SAME thread. The second proves that multiple calls to the singleton getInstance object are | ||||
|  * the same when called in the DIFFERENT thread. | ||||
|  * | ||||
|  */ | ||||
| public class LazyLoadedSingletonThreadSafetyTest { | ||||
|  | ||||
|   private static final int NUM_THREADS = 5; | ||||
|   private List<ThreadSafeLazyLoadedIvoryTower> threadObjects = Collections | ||||
|       .synchronizedList(new ArrayList<>()); | ||||
|  | ||||
|   // NullObject class so Callable has to return something | ||||
|   private class NullObject { | ||||
|     private NullObject() {} | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void testMultipleCallsReturnTheSameObjectInSameThread() { | ||||
|     // Create several instances in the same calling thread | ||||
|     ThreadSafeLazyLoadedIvoryTower instance1 = ThreadSafeLazyLoadedIvoryTower.getInstance(); | ||||
|     ThreadSafeLazyLoadedIvoryTower instance2 = ThreadSafeLazyLoadedIvoryTower.getInstance(); | ||||
|     ThreadSafeLazyLoadedIvoryTower instance3 = ThreadSafeLazyLoadedIvoryTower.getInstance(); | ||||
|     // now check they are equal | ||||
|     assertEquals(instance1, instance1); | ||||
|     assertEquals(instance1, instance2); | ||||
|     assertEquals(instance2, instance3); | ||||
|     assertEquals(instance1, instance3); | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void testMultipleCallsReturnTheSameObjectInDifferentThreads() | ||||
|       throws InterruptedException, ExecutionException { | ||||
|     { | ||||
|       // create several threads and inside each callable instantiate the singleton class | ||||
|       ExecutorService executorService = Executors.newSingleThreadExecutor(); | ||||
|  | ||||
|       List<Callable<NullObject>> threadList = new ArrayList<>(); | ||||
|       for (int i = 0; i < NUM_THREADS; i++) { | ||||
|         threadList.add(new SingletonCreatingThread()); | ||||
|       } | ||||
|  | ||||
|       ExecutorService service = Executors.newCachedThreadPool(); | ||||
|       List<Future<NullObject>> results = service.invokeAll(threadList); | ||||
|  | ||||
|       // wait for all of the threads to complete | ||||
|       for (Future res : results) { | ||||
|         res.get(); | ||||
|       } | ||||
|  | ||||
|       // tidy up the executor | ||||
|       executorService.shutdown(); | ||||
|     } | ||||
|     { | ||||
|       // now check the contents that were added to threadObjects by each thread | ||||
|       assertEquals(NUM_THREADS, threadObjects.size()); | ||||
|       assertEquals(threadObjects.get(0), threadObjects.get(1)); | ||||
|       assertEquals(threadObjects.get(1), threadObjects.get(2)); | ||||
|       assertEquals(threadObjects.get(2), threadObjects.get(3)); | ||||
|       assertEquals(threadObjects.get(3), threadObjects.get(4)); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private class SingletonCreatingThread implements Callable<NullObject> { | ||||
|     @Override | ||||
|     public NullObject call() { | ||||
|       // instantiate the thread safety class and add to list to test afterwards | ||||
|       ThreadSafeLazyLoadedIvoryTower instance = ThreadSafeLazyLoadedIvoryTower.getInstance(); | ||||
|       threadObjects.add(instance); | ||||
|       return new NullObject();// return null object (cannot return Void) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,88 @@ | ||||
| package com.iluwatar.singleton; | ||||
|  | ||||
| import org.junit.Test; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.concurrent.Callable; | ||||
| import java.util.concurrent.ExecutorService; | ||||
| import java.util.concurrent.Executors; | ||||
| import java.util.concurrent.Future; | ||||
| import java.util.function.Supplier; | ||||
|  | ||||
| import static org.junit.Assert.assertNotNull; | ||||
| import static org.junit.Assert.assertSame; | ||||
|  | ||||
| /** | ||||
|  * This class provides several test case that test singleton construction. | ||||
|  * | ||||
|  * The first proves that multiple calls to the singleton getInstance object are the same when called | ||||
|  * in the SAME thread. The second proves that multiple calls to the singleton getInstance object are | ||||
|  * the same when called in the DIFFERENT thread. | ||||
|  * | ||||
|  * Date: 12/29/15 - 19:25 PM | ||||
|  * | ||||
|  * @author Jeroen Meulemeester | ||||
|  * @author Richard Jones | ||||
|  */ | ||||
| public abstract class SingletonTest<S> { | ||||
|  | ||||
|   /** | ||||
|    * The singleton's getInstance method | ||||
|    */ | ||||
|   private final Supplier<S> singletonInstanceMethod; | ||||
|  | ||||
|   /** | ||||
|    * Create a new singleton test instance using the given 'getInstance' method | ||||
|    * | ||||
|    * @param singletonInstanceMethod The singleton's getInstance method | ||||
|    */ | ||||
|   public SingletonTest(final Supplier<S> singletonInstanceMethod) { | ||||
|     this.singletonInstanceMethod = singletonInstanceMethod; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Test the singleton in a non-concurrent setting | ||||
|    */ | ||||
|   @Test | ||||
|   public void testMultipleCallsReturnTheSameObjectInSameThread() { | ||||
|     // Create several instances in the same calling thread | ||||
|     S instance1 = this.singletonInstanceMethod.get(); | ||||
|     S instance2 = this.singletonInstanceMethod.get(); | ||||
|     S instance3 = this.singletonInstanceMethod.get(); | ||||
|     // now check they are equal | ||||
|     assertSame(instance1, instance2); | ||||
|     assertSame(instance1, instance3); | ||||
|     assertSame(instance2, instance3); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Test singleton instance in a concurrent setting | ||||
|    */ | ||||
|   @Test(timeout = 10000) | ||||
|   public void testMultipleCallsReturnTheSameObjectInDifferentThreads() throws Exception { | ||||
|  | ||||
|     // Create 10000 tasks and inside each callable instantiate the singleton class | ||||
|     final List<Callable<S>> tasks = new ArrayList<>(); | ||||
|     for (int i = 0; i < 10000; i++) { | ||||
|       tasks.add(this.singletonInstanceMethod::get); | ||||
|     } | ||||
|  | ||||
|     // Use up to 8 concurrent threads to handle the tasks | ||||
|     final ExecutorService executorService = Executors.newFixedThreadPool(8); | ||||
|     final List<Future<S>> results = executorService.invokeAll(tasks); | ||||
|  | ||||
|     // wait for all of the threads to complete | ||||
|     final S expectedInstance = this.singletonInstanceMethod.get(); | ||||
|     for (Future<S> res : results) { | ||||
|       final S instance = res.get(); | ||||
|       assertNotNull(instance); | ||||
|       assertSame(expectedInstance, instance); | ||||
|     } | ||||
|  | ||||
|     // tidy up the executor | ||||
|     executorService.shutdown(); | ||||
|  | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,17 @@ | ||||
| package com.iluwatar.singleton; | ||||
|  | ||||
| /** | ||||
|  * Date: 12/29/15 - 19:26 PM | ||||
|  * | ||||
|  * @author Jeroen Meulemeester | ||||
|  */ | ||||
| public class ThreadSafeDoubleCheckLockingTest extends SingletonTest<ThreadSafeDoubleCheckLocking> { | ||||
|  | ||||
|   /** | ||||
|    * Create a new singleton test instance using the given 'getInstance' method | ||||
|    */ | ||||
|   public ThreadSafeDoubleCheckLockingTest() { | ||||
|     super(ThreadSafeDoubleCheckLocking::getInstance); | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,17 @@ | ||||
| package com.iluwatar.singleton; | ||||
|  | ||||
| /** | ||||
|  * Date: 12/29/15 - 19:26 PM | ||||
|  * | ||||
|  * @author Jeroen Meulemeester | ||||
|  */ | ||||
| public class ThreadSafeLazyLoadedIvoryTowerTest extends SingletonTest<ThreadSafeLazyLoadedIvoryTower> { | ||||
|  | ||||
|   /** | ||||
|    * Create a new singleton test instance using the given 'getInstance' method | ||||
|    */ | ||||
|   public ThreadSafeLazyLoadedIvoryTowerTest() { | ||||
|     super(ThreadSafeLazyLoadedIvoryTower::getInstance); | ||||
|   } | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user