diff --git a/visitor/pom.xml b/visitor/pom.xml
index c51b4a7fe..b27b1da50 100644
--- a/visitor/pom.xml
+++ b/visitor/pom.xml
@@ -14,5 +14,10 @@
junit
test
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/visitor/src/test/java/com/iluwatar/visitor/CommanderTest.java b/visitor/src/test/java/com/iluwatar/visitor/CommanderTest.java
new file mode 100644
index 000000000..bbf6c7963
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/CommanderTest.java
@@ -0,0 +1,25 @@
+package com.iluwatar.visitor;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Date: 12/30/15 - 19:45 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class CommanderTest extends UnitTest {
+
+ /**
+ * Create a new test instance for the given {@link Commander}
+ */
+ public CommanderTest() {
+ super(Commander::new);
+ }
+
+ @Override
+ void verifyVisit(Commander unit, UnitVisitor mockedVisitor) {
+ verify(mockedVisitor).visitCommander(eq(unit));
+ }
+
+}
\ No newline at end of file
diff --git a/visitor/src/test/java/com/iluwatar/visitor/CommanderVisitorTest.java b/visitor/src/test/java/com/iluwatar/visitor/CommanderVisitorTest.java
new file mode 100644
index 000000000..ac296c332
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/CommanderVisitorTest.java
@@ -0,0 +1,24 @@
+package com.iluwatar.visitor;
+
+import java.util.Optional;
+
+/**
+ * Date: 12/30/15 - 18:43 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class CommanderVisitorTest extends VisitorTest {
+
+ /**
+ * Create a new test instance for the given visitor
+ */
+ public CommanderVisitorTest() {
+ super(
+ new CommanderVisitor(),
+ Optional.of("Good to see you commander"),
+ Optional.empty(),
+ Optional.empty()
+ );
+ }
+
+}
diff --git a/visitor/src/test/java/com/iluwatar/visitor/SergeantTest.java b/visitor/src/test/java/com/iluwatar/visitor/SergeantTest.java
new file mode 100644
index 000000000..d0e6d3db2
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/SergeantTest.java
@@ -0,0 +1,25 @@
+package com.iluwatar.visitor;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Date: 12/30/15 - 19:45 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SergeantTest extends UnitTest {
+
+ /**
+ * Create a new test instance for the given {@link Sergeant}
+ */
+ public SergeantTest() {
+ super(Sergeant::new);
+ }
+
+ @Override
+ void verifyVisit(Sergeant unit, UnitVisitor mockedVisitor) {
+ verify(mockedVisitor).visitSergeant(eq(unit));
+ }
+
+}
\ No newline at end of file
diff --git a/visitor/src/test/java/com/iluwatar/visitor/SergeantVisitorTest.java b/visitor/src/test/java/com/iluwatar/visitor/SergeantVisitorTest.java
new file mode 100644
index 000000000..54e274bc7
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/SergeantVisitorTest.java
@@ -0,0 +1,24 @@
+package com.iluwatar.visitor;
+
+import java.util.Optional;
+
+/**
+ * Date: 12/30/15 - 18:36 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SergeantVisitorTest extends VisitorTest {
+
+ /**
+ * Create a new test instance for the given visitor
+ */
+ public SergeantVisitorTest() {
+ super(
+ new SergeantVisitor(),
+ Optional.empty(),
+ Optional.of("Hello sergeant"),
+ Optional.empty()
+ );
+ }
+
+}
diff --git a/visitor/src/test/java/com/iluwatar/visitor/SoldierTest.java b/visitor/src/test/java/com/iluwatar/visitor/SoldierTest.java
new file mode 100644
index 000000000..e9aa54608
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/SoldierTest.java
@@ -0,0 +1,25 @@
+package com.iluwatar.visitor;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Date: 12/30/15 - 19:45 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SoldierTest extends UnitTest {
+
+ /**
+ * Create a new test instance for the given {@link Soldier}
+ */
+ public SoldierTest() {
+ super(Soldier::new);
+ }
+
+ @Override
+ void verifyVisit(Soldier unit, UnitVisitor mockedVisitor) {
+ verify(mockedVisitor).visitSoldier(eq(unit));
+ }
+
+}
\ No newline at end of file
diff --git a/visitor/src/test/java/com/iluwatar/visitor/SoldierVisitorTest.java b/visitor/src/test/java/com/iluwatar/visitor/SoldierVisitorTest.java
new file mode 100644
index 000000000..a5f16e9e3
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/SoldierVisitorTest.java
@@ -0,0 +1,24 @@
+package com.iluwatar.visitor;
+
+import java.util.Optional;
+
+/**
+ * Date: 12/30/15 - 18:59 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SoldierVisitorTest extends VisitorTest {
+
+ /**
+ * Create a new test instance for the given visitor
+ */
+ public SoldierVisitorTest() {
+ super(
+ new SoldierVisitor(),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.of("Greetings soldier")
+ );
+ }
+
+}
diff --git a/visitor/src/test/java/com/iluwatar/visitor/StdOutTest.java b/visitor/src/test/java/com/iluwatar/visitor/StdOutTest.java
new file mode 100644
index 000000000..2c54994bb
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/StdOutTest.java
@@ -0,0 +1,53 @@
+package com.iluwatar.visitor;
+
+import org.junit.After;
+import org.junit.Before;
+
+import java.io.PrintStream;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * Date: 12/10/15 - 8:37 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class StdOutTest {
+
+ /**
+ * The mocked standard out {@link PrintStream}, required since some actions don't have any
+ * influence on accessible objects, except for writing to std-out using {@link System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * Get the mocked stdOut {@link PrintStream}
+ *
+ * @return The stdOut print stream mock, renewed before each test
+ */
+ final PrintStream getStdOutMock() {
+ return this.stdOutMock;
+ }
+
+}
diff --git a/visitor/src/test/java/com/iluwatar/visitor/UnitTest.java b/visitor/src/test/java/com/iluwatar/visitor/UnitTest.java
new file mode 100644
index 000000000..291ab544a
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/UnitTest.java
@@ -0,0 +1,60 @@
+package com.iluwatar.visitor;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.function.Function;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/30/15 - 18:59 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class UnitTest {
+
+ /**
+ * Factory to create new instances of the tested unit
+ */
+ private final Function factory;
+
+ /**
+ * Create a new test instance for the given unit type {@link U}
+ *
+ * @param factory Factory to create new instances of the tested unit
+ */
+ public UnitTest(final Function factory) {
+ this.factory = factory;
+ }
+
+ @Test
+ public void testAccept() throws Exception {
+ final Unit[] children = new Unit[5];
+ Arrays.setAll(children, (i) -> mock(Unit.class));
+
+ final U unit = this.factory.apply(children);
+ final UnitVisitor visitor = mock(UnitVisitor.class);
+ unit.accept(visitor);
+ verifyVisit(unit, visitor);
+
+ for (final Unit child : children) {
+ verify(child).accept(eq(visitor));
+ }
+
+ verifyNoMoreInteractions(children);
+ verifyNoMoreInteractions(visitor);
+ }
+
+ /**
+ * Verify if the correct visit method is called on the mock, depending on the tested instance
+ *
+ * @param unit The tested unit instance
+ * @param mockedVisitor The mocked {@link UnitVisitor} who should have gotten a visit by the unit
+ */
+ abstract void verifyVisit(final U unit, final UnitVisitor mockedVisitor);
+
+}
\ No newline at end of file
diff --git a/visitor/src/test/java/com/iluwatar/visitor/VisitorTest.java b/visitor/src/test/java/com/iluwatar/visitor/VisitorTest.java
new file mode 100644
index 000000000..7bd9f03c0
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/VisitorTest.java
@@ -0,0 +1,80 @@
+package com.iluwatar.visitor;
+
+import org.junit.Test;
+
+import java.util.Optional;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/30/15 - 18:59 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class VisitorTest extends StdOutTest {
+
+ /**
+ * The tested visitor instance
+ */
+ private final V visitor;
+
+ /**
+ * The optional expected response when being visited by a commander
+ */
+ private final Optional commanderResponse;
+
+ /**
+ * The optional expected response when being visited by a sergeant
+ */
+ private final Optional sergeantResponse;
+
+ /**
+ * The optional expected response when being visited by a soldier
+ */
+ private final Optional soldierResponse;
+
+ /**
+ * Create a new test instance for the given visitor
+ *
+ * @param commanderResponse The optional expected response when being visited by a commander
+ * @param sergeantResponse The optional expected response when being visited by a sergeant
+ * @param soldierResponse The optional expected response when being visited by a soldier
+ */
+ public VisitorTest(final V visitor, final Optional commanderResponse,
+ final Optional sergeantResponse, final Optional soldierResponse) {
+
+ this.visitor = visitor;
+ this.commanderResponse = commanderResponse;
+ this.sergeantResponse = sergeantResponse;
+ this.soldierResponse = soldierResponse;
+ }
+
+ @Test
+ public void testVisitCommander() {
+ this.visitor.visitCommander(new Commander());
+ if (this.commanderResponse.isPresent()) {
+ verify(getStdOutMock()).println(this.commanderResponse.get());
+ }
+ verifyNoMoreInteractions(getStdOutMock());
+ }
+
+ @Test
+ public void testVisitSergeant() {
+ this.visitor.visitSergeant(new Sergeant());
+ if (this.sergeantResponse.isPresent()) {
+ verify(getStdOutMock()).println(this.sergeantResponse.get());
+ }
+ verifyNoMoreInteractions(getStdOutMock());
+ }
+
+ @Test
+ public void testVisitSoldier() {
+ this.visitor.visitSoldier(new Soldier());
+ if (this.soldierResponse.isPresent()) {
+ verify(getStdOutMock()).println(this.soldierResponse.get());
+ }
+ verifyNoMoreInteractions(getStdOutMock());
+ }
+
+}