Added tests for singleton pattern
This commit is contained in:
parent
a375b2d28b
commit
d0cdf84936
@ -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);
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user