testingreflections / NarrativeFixture (http://pairwith.us/current-project.html)
New Narrative Fixture as featured in http://pairwith.us
$ hg clone http://bitbucket.org/testingreflections/narrativefixture/
| commit 44: | adc0b4871fe8 |
| parent 43: | b4029fbec56f |
| branch: | default |
| tags: | tip |
8 months ago
Changed (Δ7.1 KB):
src/org/jnarrate/fit/fixture/NarrativeFixture.java (2 lines added, 2 lines removed)
src/org/jnarrate/fit/fixture/entityname/Information.java
src/org/jnarrate/fit/fixture/expertise/Clerk.java (87 lines added, 0 lines removed)
src/org/jnarrate/fit/fixture/expertise/SubjectMatterExpert.java (2 lines added, 3 lines removed)
src/org/jnarrate/fit/fixture/expertise/misuse/InvokedCodeComplainedComplaint.java (12 lines added, 0 lines removed)
src/org/jnarrate/fit/fixture/expertise/misuse/UnableToFillInDetailsComplaint.java (11 lines added, 0 lines removed)
test/org/jnarrate/fit/fixture/NarrativeFixtureTest.java (2 lines added, 2 lines removed)
test/org/jnarrate/fit/fixture/entityname/ClerkShould.java (89 lines added, 0 lines removed)
test/org/jnarrate/fit/fixture/entityname/InformationShould.java
test/org/jnarrate/fit/fixture/entityname/information/ActionWithAMethodName.java
test/org/jnarrate/fit/fixture/entityname/information/ObjectWithAMethodName.java (9 lines added, 0 lines removed)
test/org/jnarrate/fit/fixture/expertise/SubjectMatterExpertTest.java (3 lines added, 4 lines removed)
Up to file-list src/org/jnarrate/fit/fixture/NarrativeFixture.java:
| … | … | @@ -8,10 +8,10 @@ import org.jnarrate.action.PerformableAs |
8 |
8 |
import org.jnarrate.fit.fixture.entityname.ActionName; |
9 |
9 |
import org.jnarrate.fit.fixture.entityname.CharacterName; |
10 |
10 |
import org.jnarrate.fit.fixture.entityname.Demographic; |
11 |
import org.jnarrate.fit.fixture.entityname.Information; |
|
12 |
11 |
import org.jnarrate.fit.fixture.entityname.QuestionName; |
13 |
12 |
import org.jnarrate.fit.fixture.entityname.RoleName; |
14 |
13 |
import org.jnarrate.fit.fixture.expertise.CastingDirector; |
14 |
import org.jnarrate.fit.fixture.expertise.Clerk; |
|
15 |
15 |
import org.jnarrate.fit.fixture.expertise.SubjectMatterExpert; |
16 |
16 |
import org.jnarrate.question.AnswerableBy; |
17 |
17 |
import org.jnarrate.sugar.Given; |
| … | … | @@ -60,7 +60,7 @@ public class NarrativeFixture extends Do |
60 |
60 |
|
61 |
61 |
public <ROLE> void whenAttemptsToWith(String theCharacter, String doThis, String thisInformation) { |
62 |
62 |
ActorPlayingThe<ROLE> actor = castingDirector.whoIsPlaying(new CharacterName(theCharacter)); |
63 |
PerformableAsA<ROLE> doThisAction = sme.howDoI(new ActionName(doThis), new |
|
63 |
PerformableAsA<ROLE> doThisAction = sme.howDoI(new ActionName(doThis), new Clerk(thisInformation)); |
|
64 |
64 |
|
65 |
65 |
When.the(actor).attemptsTo(doThisAction); |
66 |
66 |
} |
Up to file-list src/org/jnarrate/fit/fixture/expertise/Clerk.java:
1 |
package org.jnarrate.fit.fixture.expertise; |
|
2 |
||
3 |
import java.lang.reflect.InvocationTargetException; |
|
4 |
import java.lang.reflect.Method; |
|
5 |
import java.util.regex.Matcher; |
|
6 |
import java.util.regex.Pattern; |
|
7 |
||
8 |
import org.jnarrate.fit.fixture.entityname.MethodName; |
|
9 |
import org.jnarrate.fit.fixture.expertise.misuse.InvokedCodeComplainedComplaint; |
|
10 |
import org.jnarrate.fit.fixture.expertise.misuse.UnableToFillInDetailsComplaint; |
|
11 |
||
12 |
public class Clerk { |
|
13 |
||
14 |
private static final String BEFORE_THE_FIRST_QUOTE = "^(.*) \""; |
|
15 |
private static final String INSIDE_QUOTES = "\"(.*)\""; |
|
16 |
private final String value; |
|
17 |
private final MethodName methodName; |
|
18 |
||
19 |
public Clerk(String fromThisSentenceFragment) { |
|
20 |
methodName = new MethodName(theText(BEFORE_THE_FIRST_QUOTE,fromThisSentenceFragment)); |
|
21 |
value = theText(INSIDE_QUOTES, fromThisSentenceFragment); |
|
22 |
} |
|
23 |
private String theText(String thisPattern, String fromThisSentenceFragment) { |
|
24 |
Pattern valuePattern = Pattern.compile(thisPattern); |
|
25 |
Matcher matcher = valuePattern.matcher(fromThisSentenceFragment); |
|
26 |
matcher.find(); |
|
27 |
return matcher.group(1); |
|
28 |
} |
|
29 |
||
30 |
public <T> T addTheDetailsTo(T lookedUpAction) { |
|
31 |
try { |
|
32 |
Method method = lookedUpAction.getClass().getMethod(methodName.toString(), String.class); |
|
33 |
method.invoke(lookedUpAction, value); |
|
34 |
return lookedUpAction; |
|
35 |
} |
|
36 |
catch (NoSuchMethodException e) { |
|
37 |
throw new UnableToFillInDetailsComplaint(lookedUpAction, methodName, e); |
|
38 |
} |
|
39 |
catch (InvocationTargetException e) { |
|
40 |
throw new InvokedCodeComplainedComplaint(lookedUpAction, methodName, e); |
|
41 |
} |
|
42 |
catch (SecurityException e) { |
|
43 |
throw new RuntimeException("TODO - Handle this exception better",e); |
|
44 |
} |
|
45 |
catch (IllegalArgumentException e) { |
|
46 |
throw new RuntimeException("TODO - Handle this exception better",e); |
|
47 |
} |
|
48 |
catch (IllegalAccessException e) { |
|
49 |
throw new RuntimeException("TODO - Handle this exception better",e); |
|
50 |
} |
|
51 |
} |
|
52 |
||
53 |
@Override |
|
54 |
public int hashCode() { |
|
55 |
final int prime = 31; |
|
56 |
int result = 1; |
|
57 |
result = prime * result + ((methodName == null) ? 0 : methodName.hashCode()); |
|
58 |
result = prime * result + ((value == null) ? 0 : value.hashCode()); |
|
59 |
return result; |
|
60 |
} |
|
61 |
||
62 |
@Override |
|
63 |
public boolean equals(Object obj) { |
|
64 |
if (this == obj) |
|
65 |
return true; |
|
66 |
if (obj == null) |
|
67 |
return false; |
|
68 |
if (getClass() != obj.getClass()) |
|
69 |
return false; |
|
70 |
Clerk other = (Clerk) obj; |
|
71 |
if (methodName == null) { |
|
72 |
if (other.methodName != null) |
|
73 |
return false; |
|
74 |
} |
|
75 |
else if (!methodName.equals(other.methodName)) |
|
76 |
return false; |
|
77 |
if (value == null) { |
|
78 |
if (other.value != null) |
|
79 |
return false; |
|
80 |
} |
|
81 |
else if (!value.equals(other.value)) |
|
82 |
return false; |
|
83 |
return true; |
|
84 |
} |
|
85 |
||
86 |
||
87 |
} |
Up to file-list src/org/jnarrate/fit/fixture/expertise/SubjectMatterExpert.java:
| … | … | @@ -5,7 +5,6 @@ import org.jnarrate.expertise.Librarian; |
5 |
5 |
import org.jnarrate.expertise.library.index.ClassName; |
6 |
6 |
import org.jnarrate.expertise.library.index.PackageName; |
7 |
7 |
import org.jnarrate.fit.fixture.entityname.ActionName; |
8 |
import org.jnarrate.fit.fixture.entityname.Information; |
|
9 |
8 |
import org.jnarrate.fit.fixture.entityname.QuestionName; |
10 |
9 |
import org.jnarrate.fit.fixture.expertise.misuse.NotAnActionComplaint; |
11 |
10 |
import org.jnarrate.question.AnswerableBy; |
| … | … | @@ -34,9 +33,9 @@ public class SubjectMatterExpert { |
34 |
33 |
} |
35 |
34 |
} |
36 |
35 |
|
37 |
public <ROLE> PerformableAsA<ROLE> howDoI(ActionName actionName, |
|
36 |
public <ROLE> PerformableAsA<ROLE> howDoI(ActionName actionName, Clerk information) { |
|
38 |
37 |
PerformableAsA<ROLE> action = howDoI(actionName); |
39 |
return information.add |
|
38 |
return information.addTheDetailsTo(action); |
|
40 |
39 |
} |
41 |
40 |
|
42 |
41 |
public <ROLE, T> AnswerableBy<ROLE, T> howDoIAnswer(QuestionName questionName) { |
Up to file-list src/org/jnarrate/fit/fixture/expertise/misuse/InvokedCodeComplainedComplaint.java:
1 |
package org.jnarrate.fit.fixture.expertise.misuse; |
|
2 |
||
3 |
import java.lang.reflect.InvocationTargetException; |
|
4 |
import org.jnarrate.fit.fixture.entityname.MethodName; |
|
5 |
||
6 |
public class InvokedCodeComplainedComplaint extends RuntimeException { |
|
7 |
||
8 |
public InvokedCodeComplainedComplaint(Object invokedAction, MethodName methodName, InvocationTargetException wrappedException) { |
|
9 |
super("The method ["+ methodName +"] on the class ["+ invokedAction.getClass().getCanonicalName() +"] complained with ["+ wrappedException.getCause().getClass().getSimpleName() +"]", wrappedException.getCause() ); |
|
10 |
} |
|
11 |
||
12 |
} |
Up to file-list src/org/jnarrate/fit/fixture/expertise/misuse/UnableToFillInDetailsComplaint.java:
1 |
package org.jnarrate.fit.fixture.expertise.misuse; |
|
2 |
||
3 |
import org.jnarrate.fit.fixture.entityname.MethodName; |
|
4 |
||
5 |
public class UnableToFillInDetailsComplaint extends RuntimeException { |
|
6 |
||
7 |
public UnableToFillInDetailsComplaint(Object invokedAction, MethodName methodName, Exception wrappedException) { |
|
8 |
super("Unable to find a method called [" + methodName + "] with a String parameter on the class [" + invokedAction.getClass().getCanonicalName() + "]. Maybe you should create it", wrappedException); |
|
9 |
} |
|
10 |
||
11 |
} |
Up to file-list test/org/jnarrate/fit/fixture/NarrativeFixtureTest.java:
| … | … | @@ -16,10 +16,10 @@ import org.jnarrate.action.PerformableAs |
16 |
16 |
import org.jnarrate.fit.fixture.entityname.ActionName; |
17 |
17 |
import org.jnarrate.fit.fixture.entityname.CharacterName; |
18 |
18 |
import org.jnarrate.fit.fixture.entityname.Demographic; |
19 |
import org.jnarrate.fit.fixture.entityname.Information; |
|
20 |
19 |
import org.jnarrate.fit.fixture.entityname.QuestionName; |
21 |
20 |
import org.jnarrate.fit.fixture.entityname.RoleName; |
22 |
21 |
import org.jnarrate.fit.fixture.expertise.CastingDirector; |
22 |
import org.jnarrate.fit.fixture.expertise.Clerk; |
|
23 |
23 |
import org.jnarrate.fit.fixture.expertise.SubjectMatterExpert; |
24 |
24 |
import org.jnarrate.question.AnswerableBy; |
25 |
25 |
import org.jnarrate.question.Question; |
| … | … | @@ -154,7 +154,7 @@ public class NarrativeFixtureTest { |
154 |
154 |
andThatItIsAsked(castingDirector.whoIsPlaying(new CharacterName(theRole))).thenReturn((ActorPlayingThe) actor); |
155 |
155 |
|
156 |
156 |
givenThatWeHaveASubjectMatterExpertPlayedByThis(mock(SubjectMatterExpert.class)); |
157 |
andThatItIsAsked(sme.howDoI(new ActionName(doThis), new |
|
157 |
andThatItIsAsked(sme.howDoI(new ActionName(doThis), new Clerk(thisInformation))).thenReturn((PerformableAsA) action); |
|
158 |
158 |
|
159 |
159 |
NarrativeFixture narrativeFixture = new NarrativeFixture(castingDirector, sme); |
160 |
160 |
narrativeFixture.whenAttemptsToWith(theRole, doThis, thisInformation); |
Up to file-list test/org/jnarrate/fit/fixture/entityname/ClerkShould.java:
1 |
package org.jnarrate.fit.fixture.entityname; |
|
2 |
||
3 |
import static org.hamcrest.CoreMatchers.instanceOf; |
|
4 |
import static org.hamcrest.CoreMatchers.is; |
|
5 |
import static org.junit.Assert.assertThat; |
|
6 |
import static org.mockito.Mockito.doThrow; |
|
7 |
import static org.mockito.Mockito.mock; |
|
8 |
import static org.mockito.Mockito.verify; |
|
9 |
||
10 |
import org.jnarrate.fit.fixture.entityname.information.ObjectWithAMethodName; |
|
11 |
import org.jnarrate.fit.fixture.expertise.Clerk; |
|
12 |
import org.jnarrate.fit.fixture.expertise.misuse.InvokedCodeComplainedComplaint; |
|
13 |
import org.jnarrate.fit.fixture.expertise.misuse.UnableToFillInDetailsComplaint; |
|
14 |
import org.junit.Test; |
|
15 |
||
16 |
public class ClerkShould { |
|
17 |
||
18 |
@Test |
|
19 |
public void informTheThing() throws Exception { |
|
20 |
String withTheseDetails = "aMethodName \"a value\""; |
|
21 |
||
22 |
ObjectWithAMethodName theThing = mock(ObjectWithAMethodName.class); |
|
23 |
Clerk clerk = new Clerk(withTheseDetails); |
|
24 |
||
25 |
ObjectWithAMethodName informedThing = clerk.addTheDetailsTo(theThing); |
|
26 |
||
27 |
verify(theThing).aMethodName("a value"); |
|
28 |
assertThat(informedThing, is(instanceOf(ObjectWithAMethodName.class))); |
|
29 |
} |
|
30 |
||
31 |
@Test |
|
32 |
public void informTheThingWithADifferentValue() throws Exception { |
|
33 |
String withTheseDetails = "aMethodName \"a different value\""; |
|
34 |
||
35 |
ObjectWithAMethodName theThing = mock(ObjectWithAMethodName.class); |
|
36 |
Clerk clerk = new Clerk(withTheseDetails); |
|
37 |
||
38 |
ObjectWithAMethodName informedThing = clerk.addTheDetailsTo(theThing); |
|
39 |
||
40 |
verify(theThing).aMethodName("a different value"); |
|
41 |
assertThat(informedThing, is(instanceOf(ObjectWithAMethodName.class))); |
|
42 |
} |
|
43 |
||
44 |
@Test |
|
45 |
public void informTheThingWithADifferentMethod() throws Exception { |
|
46 |
String withTheseDetails = "a Different Method Name \"a value\""; |
|
47 |
||
48 |
ObjectWithAMethodName theThing = mock(ObjectWithAMethodName.class); |
|
49 |
Clerk clerk = new Clerk(withTheseDetails); |
|
50 |
||
51 |
ObjectWithAMethodName informedThing = clerk.addTheDetailsTo(theThing); |
|
52 |
||
53 |
verify(theThing).aDifferentMethodName("a value"); |
|
54 |
assertThat(informedThing, is(instanceOf(ObjectWithAMethodName.class))); |
|
55 |
} |
|
56 |
||
57 |
@Test |
|
58 |
public void complainWhenNoAppropriateMethod() throws Exception { |
|
59 |
Clerk clerk = new Clerk("a method that is \"not there\""); |
|
60 |
ObjectWithAMethodName thing = mock(ObjectWithAMethodName.class); |
|
61 |
||
62 |
Exception thrown = null; |
|
63 |
try { |
|
64 |
clerk.addTheDetailsTo(thing); |
|
65 |
} |
|
66 |
catch (Exception caught) { |
|
67 |
thrown = caught; |
|
68 |
} |
|
69 |
||
70 |
assertThat(thrown, is(instanceOf(UnableToFillInDetailsComplaint.class))); |
|
71 |
} |
|
72 |
||
73 |
@Test |
|
74 |
public void complainWhenCalledMethodComplains() throws Exception { |
|
75 |
Clerk clerk = new Clerk("a method name \"but it complains\""); |
|
76 |
ObjectWithAMethodName thing = mock(ObjectWithAMethodName.class); |
|
77 |
doThrow(new UnsupportedOperationException("Whoops!")).when(thing).aMethodName("but it complains"); |
|
78 |
||
79 |
Exception thrown = null; |
|
80 |
try { |
|
81 |
clerk.addTheDetailsTo(thing); |
|
82 |
} |
|
83 |
catch (Exception caught) { |
|
84 |
thrown = caught; |
|
85 |
} |
|
86 |
||
87 |
assertThat(thrown, is(instanceOf(InvokedCodeComplainedComplaint.class))); |
|
88 |
} |
|
89 |
} |
Up to file-list test/org/jnarrate/fit/fixture/entityname/information/ObjectWithAMethodName.java:
1 |
package org.jnarrate.fit.fixture.entityname.information; |
|
2 |
||
3 |
||
4 |
public interface ObjectWithAMethodName { |
|
5 |
||
6 |
void aMethodName(String aValue); |
|
7 |
void aDifferentMethodName(String string); |
|
8 |
void aMethodWithNoParameter(); |
|
9 |
} |
Up to file-list test/org/jnarrate/fit/fixture/expertise/SubjectMatterExpertTest.java:
| … | … | @@ -15,7 +15,6 @@ import org.jnarrate.action.PerformableAs |
15 |
15 |
import org.jnarrate.expertise.Librarian; |
16 |
16 |
import org.jnarrate.expertise.library.index.PackageName; |
17 |
17 |
import org.jnarrate.fit.fixture.entityname.ActionName; |
18 |
import org.jnarrate.fit.fixture.entityname.Information; |
|
19 |
18 |
import org.jnarrate.fit.fixture.entityname.QuestionName; |
20 |
19 |
import org.jnarrate.fit.fixture.expertise.misuse.NotAnActionComplaint; |
21 |
20 |
import org.jnarrate.question.AnswerableBy; |
| … | … | @@ -45,13 +44,13 @@ public class SubjectMatterExpertTest { |
45 |
44 |
when(librarian.findMeA(new ActionName("Dummy Action"), new PackageName("org.jnarrate.action"))).thenReturn(lookedUpAction); |
46 |
45 |
|
47 |
46 |
SubjectMatterExpert sme = new SubjectMatterExpert(librarian); |
48 |
|
|
47 |
Clerk information = mock(Clerk.class); |
|
49 |
48 |
PerformableAsA<ROLE> informedAction = mock(PerformableAsA.class); |
50 |
when(information.add |
|
49 |
when(information.addTheDetailsTo(lookedUpAction)).thenReturn(informedAction); |
|
51 |
50 |
|
52 |
51 |
PerformableAsA<ROLE> result = sme.howDoI(new ActionName("Dummy Action"), information); |
53 |
52 |
|
54 |
verify(information).add |
|
53 |
verify(information).addTheDetailsTo(lookedUpAction); |
|
55 |
54 |
assertThat(result, is(sameInstance(informedAction))); |
56 |
55 |
} |
57 |
56 |
