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