Skip to content

Commit c837ffe

Browse files
committed
Add proper unit tests for double-dispatch pattern
1 parent 2edc189 commit c837ffe

7 files changed

Lines changed: 524 additions & 9 deletions

File tree

double-dispatch/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,10 @@
1414
<artifactId>junit</artifactId>
1515
<scope>test</scope>
1616
</dependency>
17+
<dependency>
18+
<groupId>org.mockito</groupId>
19+
<artifactId>mockito-core</artifactId>
20+
<scope>test</scope>
21+
</dependency>
1722
</dependencies>
1823
</project>
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package com.iluwatar.doubledispatch;
2+
3+
import org.junit.After;
4+
import org.junit.Before;
5+
6+
import java.io.PrintStream;
7+
import java.util.Objects;
8+
9+
import static org.junit.Assert.assertEquals;
10+
import static org.mockito.Mockito.mock;
11+
import static org.mockito.Mockito.times;
12+
import static org.mockito.Mockito.verify;
13+
import static org.mockito.Mockito.verifyNoMoreInteractions;
14+
15+
/**
16+
* Date: 12/10/15 - 8:37 PM
17+
*
18+
* @author Jeroen Meulemeester
19+
*/
20+
public abstract class CollisionTest<O extends GameObject> {
21+
22+
/**
23+
* The mocked standard out {@link PrintStream}, required if some of the actions on the tested
24+
* object don't have a direct influence on any other accessible objects, except for writing to
25+
* std-out using {@link System#out}
26+
*/
27+
private final PrintStream stdOutMock = mock(PrintStream.class);
28+
29+
/**
30+
* Keep the original std-out so it can be restored after the test
31+
*/
32+
private final PrintStream stdOutOrig = System.out;
33+
34+
/**
35+
* Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
36+
*/
37+
@Before
38+
public void setUp() {
39+
System.setOut(this.stdOutMock);
40+
}
41+
42+
/**
43+
* Removed the mocked std-out {@link PrintStream} again from the {@link System} class
44+
*/
45+
@After
46+
public void tearDown() {
47+
System.setOut(this.stdOutOrig);
48+
}
49+
50+
/**
51+
* Get the mocked stdOut {@link PrintStream}
52+
*
53+
* @return The stdOut print stream mock, renewed before each test
54+
*/
55+
final PrintStream getStdOutMock() {
56+
return this.stdOutMock;
57+
}
58+
59+
/**
60+
* Get the tested object
61+
*
62+
* @return The tested object, should never return 'null'
63+
*/
64+
abstract O getTestedObject();
65+
66+
/**
67+
* Collide the tested item with the other given item and verify if the damage and fire state is as
68+
* expected
69+
*
70+
* @param other The other object we have to collide with
71+
* @param otherDamaged Indicates if the other object should be damaged after the collision
72+
* @param otherOnFire Indicates if the other object should be burning after the collision
73+
* @param thisDamaged Indicates if the test object should be damaged after the collision
74+
* @param thisOnFire Indicates if the other object should be burning after the collision
75+
* @param description The expected description of the collision
76+
*/
77+
void testCollision(final GameObject other, final boolean otherDamaged, final boolean otherOnFire,
78+
final boolean thisDamaged, final boolean thisOnFire, final String description) {
79+
80+
Objects.requireNonNull(other);
81+
Objects.requireNonNull(getTestedObject());
82+
83+
final O tested = getTestedObject();
84+
85+
tested.collision(other);
86+
87+
verify(getStdOutMock(), times(1)).println(description);
88+
verifyNoMoreInteractions(getStdOutMock());
89+
90+
testOnFire(other, tested, otherOnFire);
91+
testDamaged(other, tested, otherDamaged);
92+
93+
testOnFire(tested, other, thisOnFire);
94+
testDamaged(tested, other, thisDamaged);
95+
96+
}
97+
98+
/**
99+
* Test if the fire state of the target matches the expected state after colliding with the given
100+
* object
101+
*
102+
* @param target The target object
103+
* @param other The other object
104+
* @param expectTargetOnFire The expected state of fire on the target object
105+
*/
106+
private void testOnFire(final GameObject target, final GameObject other, final boolean expectTargetOnFire) {
107+
final String targetName = target.getClass().getSimpleName();
108+
final String otherName = other.getClass().getSimpleName();
109+
110+
final String errorMessage = expectTargetOnFire ?
111+
"Expected [" + targetName + "] to be on fire after colliding with [" + otherName + "] but it was not!" :
112+
"Expected [" + targetName + "] not to be on fire after colliding with [" + otherName + "] but it was!";
113+
114+
assertEquals(errorMessage, expectTargetOnFire, target.isOnFire());
115+
}
116+
117+
/**
118+
* Test if the damage state of the target matches the expected state after colliding with the
119+
* given object
120+
*
121+
* @param target The target object
122+
* @param other The other object
123+
* @param expectedDamage The expected state of damage on the target object
124+
*/
125+
private void testDamaged(final GameObject target, final GameObject other, final boolean expectedDamage) {
126+
final String targetName = target.getClass().getSimpleName();
127+
final String otherName = other.getClass().getSimpleName();
128+
129+
final String errorMessage = expectedDamage ?
130+
"Expected [" + targetName + "] to be damaged after colliding with [" + otherName + "] but it was not!" :
131+
"Expected [" + targetName + "] not to be damaged after colliding with [" + otherName + "] but it was!";
132+
133+
assertEquals(errorMessage, expectedDamage, target.isDamaged());
134+
}
135+
136+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package com.iluwatar.doubledispatch;
2+
3+
import org.junit.Test;
4+
5+
import static org.junit.Assert.assertEquals;
6+
import static org.junit.Assert.assertFalse;
7+
import static org.junit.Assert.assertTrue;
8+
9+
/**
10+
* Date: 12/10/15 - 11:31 PM
11+
*
12+
* @author Jeroen Meulemeester
13+
*/
14+
public class FlamingAsteroidTest extends CollisionTest<FlamingAsteroid> {
15+
16+
@Override
17+
final FlamingAsteroid getTestedObject() {
18+
return new FlamingAsteroid(1, 2, 3, 4);
19+
}
20+
21+
/**
22+
* Test the constructor parameters
23+
*/
24+
@Test
25+
public void testConstructor() {
26+
final FlamingAsteroid asteroid = new FlamingAsteroid(1, 2, 3, 4);
27+
assertEquals(1, asteroid.getLeft());
28+
assertEquals(2, asteroid.getTop());
29+
assertEquals(3, asteroid.getRight());
30+
assertEquals(4, asteroid.getBottom());
31+
assertTrue(asteroid.isOnFire());
32+
assertFalse(asteroid.isDamaged());
33+
assertEquals("FlamingAsteroid at [1,2,3,4] damaged=false onFire=true", asteroid.toString());
34+
}
35+
36+
/**
37+
* Test what happens we collide with an asteroid
38+
*/
39+
@Test
40+
public void testCollideFlamingAsteroid() {
41+
testCollision(
42+
new FlamingAsteroid(1, 2, 3, 4),
43+
false, true,
44+
false, true,
45+
"FlamingAsteroid hits FlamingAsteroid."
46+
);
47+
}
48+
49+
/**
50+
* Test what happens we collide with an meteoroid
51+
*/
52+
@Test
53+
public void testCollideMeteoroid() {
54+
testCollision(
55+
new Meteoroid(1, 1, 3, 4),
56+
false, false,
57+
false, true,
58+
"FlamingAsteroid hits Meteoroid."
59+
);
60+
}
61+
62+
/**
63+
* Test what happens we collide with ISS
64+
*/
65+
@Test
66+
public void testCollideSpaceStationIss() {
67+
testCollision(
68+
new SpaceStationIss(1, 1, 3, 4),
69+
true, true,
70+
false, true,
71+
"FlamingAsteroid hits SpaceStationIss. SpaceStationIss is damaged! SpaceStationIss is set on fire!"
72+
);
73+
}
74+
75+
/**
76+
* Test what happens we collide with MIR
77+
*/
78+
@Test
79+
public void testCollideSpaceStationMir() {
80+
testCollision(
81+
new SpaceStationMir(1, 1, 3, 4),
82+
true, true,
83+
false, true,
84+
"FlamingAsteroid hits SpaceStationMir. SpaceStationMir is damaged! SpaceStationMir is set on fire!"
85+
);
86+
}
87+
88+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.iluwatar.doubledispatch;
2+
3+
import org.junit.Test;
4+
5+
import static org.junit.Assert.assertEquals;
6+
import static org.junit.Assert.assertFalse;
7+
8+
/**
9+
* Date: 12/10/15 - 11:31 PM
10+
*
11+
* @author Jeroen Meulemeester
12+
*/
13+
public class MeteoroidTest extends CollisionTest<Meteoroid> {
14+
15+
@Override
16+
final Meteoroid getTestedObject() {
17+
return new Meteoroid(1, 2, 3, 4);
18+
}
19+
20+
/**
21+
* Test the constructor parameters
22+
*/
23+
@Test
24+
public void testConstructor() {
25+
final Meteoroid meteoroid = new Meteoroid(1, 2, 3, 4);
26+
assertEquals(1, meteoroid.getLeft());
27+
assertEquals(2, meteoroid.getTop());
28+
assertEquals(3, meteoroid.getRight());
29+
assertEquals(4, meteoroid.getBottom());
30+
assertFalse(meteoroid.isOnFire());
31+
assertFalse(meteoroid.isDamaged());
32+
assertEquals("Meteoroid at [1,2,3,4] damaged=false onFire=false", meteoroid.toString());
33+
}
34+
35+
/**
36+
* Test what happens we collide with an asteroid
37+
*/
38+
@Test
39+
public void testCollideFlamingAsteroid() {
40+
testCollision(
41+
new FlamingAsteroid(1, 1, 3, 4),
42+
false, true,
43+
false, false,
44+
"Meteoroid hits FlamingAsteroid."
45+
);
46+
}
47+
48+
/**
49+
* Test what happens we collide with an meteoroid
50+
*/
51+
@Test
52+
public void testCollideMeteoroid() {
53+
testCollision(
54+
new Meteoroid(1, 1, 3, 4),
55+
false, false,
56+
false, false,
57+
"Meteoroid hits Meteoroid."
58+
);
59+
}
60+
61+
/**
62+
* Test what happens we collide with ISS
63+
*/
64+
@Test
65+
public void testCollideSpaceStationIss() {
66+
testCollision(
67+
new SpaceStationIss(1, 1, 3, 4),
68+
true, false,
69+
false, false,
70+
"Meteoroid hits SpaceStationIss. SpaceStationIss is damaged!"
71+
);
72+
}
73+
74+
/**
75+
* Test what happens we collide with MIR
76+
*/
77+
@Test
78+
public void testCollideSpaceStationMir() {
79+
testCollision(
80+
new SpaceStationMir(1, 1, 3, 4),
81+
true, false,
82+
false, false,
83+
"Meteoroid hits SpaceStationMir. SpaceStationMir is damaged!"
84+
);
85+
}
86+
87+
}
Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,47 @@
11
package com.iluwatar.doubledispatch;
22

3-
import org.junit.Assert;
43
import org.junit.Test;
54

6-
import com.iluwatar.doubledispatch.Rectangle;
5+
import static junit.framework.TestCase.assertEquals;
6+
import static org.junit.Assert.assertFalse;
7+
import static org.junit.Assert.assertTrue;
78

89
/**
9-
*
1010
* Unit test for Rectangle
11-
*
1211
*/
1312
public class RectangleTest {
1413

14+
/**
15+
* Test if the values passed through the constructor matches the values fetched from the getters
16+
*/
1517
@Test
16-
public void test() {
17-
Assert.assertTrue(new Rectangle(0, 0, 1, 1).intersectsWith(new Rectangle(0, 0, 1, 1)));
18-
Assert.assertTrue(new Rectangle(0, 0, 1, 1).intersectsWith(new Rectangle(-1, -5, 7, 8)));
19-
Assert.assertFalse(new Rectangle(0, 0, 1, 1).intersectsWith(new Rectangle(2, 2, 3, 3)));
20-
Assert.assertFalse(new Rectangle(0, 0, 1, 1).intersectsWith(new Rectangle(-2, -2, -1, -1)));
18+
public void testConstructor() {
19+
final Rectangle rectangle = new Rectangle(1, 2, 3, 4);
20+
assertEquals(1, rectangle.getLeft());
21+
assertEquals(2, rectangle.getTop());
22+
assertEquals(3, rectangle.getRight());
23+
assertEquals(4, rectangle.getBottom());
2124
}
25+
26+
/**
27+
* Test if the values passed through the constructor matches the values in the {@link
28+
* #toString()}
29+
*/
30+
@Test
31+
public void testToString() throws Exception {
32+
final Rectangle rectangle = new Rectangle(1, 2, 3, 4);
33+
assertEquals("[1,2,3,4]", rectangle.toString());
34+
}
35+
36+
/**
37+
* Test if the {@link Rectangle} class can detect if it intersects with another rectangle.
38+
*/
39+
@Test
40+
public void testIntersection() {
41+
assertTrue(new Rectangle(0, 0, 1, 1).intersectsWith(new Rectangle(0, 0, 1, 1)));
42+
assertTrue(new Rectangle(0, 0, 1, 1).intersectsWith(new Rectangle(-1, -5, 7, 8)));
43+
assertFalse(new Rectangle(0, 0, 1, 1).intersectsWith(new Rectangle(2, 2, 3, 3)));
44+
assertFalse(new Rectangle(0, 0, 1, 1).intersectsWith(new Rectangle(-2, -2, -1, -1)));
45+
}
46+
2247
}

0 commit comments

Comments
 (0)