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