Skip to content

Commit bdca505

Browse files
author
Sylvain Fraïssé
committed
refact: new run test cases implementation
To increase readability and testability, the code has been split into many little methods.
1 parent e5bf982 commit bdca505

File tree

7 files changed

+407
-0
lines changed

7 files changed

+407
-0
lines changed

pom.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@
3737
<artifactId>mockito-core</artifactId>
3838
<version>2.6.8</version>
3939
</dependency>
40+
<dependency>
41+
<groupId>io.vertx</groupId>
42+
<artifactId>vertx-core</artifactId>
43+
<version>3.0.0</version>
44+
<scope>test</scope>
45+
</dependency>
46+
<dependency>
47+
<groupId>io.vertx</groupId>
48+
<artifactId>vertx-unit</artifactId>
49+
<version>3.0.0</version>
50+
<scope>test</scope>
51+
</dependency>
4052
</dependencies>
4153

4254
<build>
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package com.codingame.codemachine.runner.junit;
2+
3+
import com.codingame.codemachine.runner.junit.core.TestResultDto;
4+
import com.google.gson.Gson;
5+
import org.apache.commons.io.FileUtils;
6+
import org.junit.internal.runners.ErrorReportingRunner;
7+
import org.junit.runner.JUnitCore;
8+
import org.junit.runner.Request;
9+
import org.junit.runner.Runner;
10+
11+
import java.io.File;
12+
import java.io.IOException;
13+
import java.io.PrintStream;
14+
import java.util.ArrayList;
15+
import java.util.List;
16+
import java.util.regex.Matcher;
17+
import java.util.regex.Pattern;
18+
19+
public class JUnitTest {
20+
private static final String DEFAULT_OUTPUT = "-";
21+
private static final Pattern COMMAND_PATTERN = Pattern.compile("(?<class>[^#]+)(?:#(?<method>[^#]+))?");
22+
23+
private final PrintStream realOut;
24+
private final PrintStream realErr;
25+
private final JUnitCore jUnitCore;
26+
private List<TestResultDto> results;
27+
private boolean oneFailure;
28+
29+
JUnitTest() {
30+
realOut = System.out;
31+
realErr = System.err;
32+
jUnitCore = new JUnitCore();
33+
oneFailure = false;
34+
}
35+
36+
boolean isOneFailure() {
37+
return this.oneFailure;
38+
}
39+
40+
int run(String... args) {
41+
List<TestCase> testCases = findRequests(args);
42+
runTestCases(testCases);
43+
44+
int statusCode = isOneFailure() ? 1 : 0;
45+
statusCode = generateResult() ? statusCode : 3;
46+
47+
return statusCode;
48+
}
49+
50+
List<TestCase> findRequests(String... args) {
51+
List<TestCase> requests = new ArrayList<>();
52+
for (String arg : args) {
53+
Matcher matcher = COMMAND_PATTERN.matcher(arg);
54+
if (matcher.matches()) {
55+
try {
56+
Class<?> clazz = Class.forName(matcher.group("class"));
57+
String method = matcher.group("method");
58+
if (method != null) {
59+
requests.add(TestCase.createTestCase(Request.method(clazz, method), arg));
60+
}
61+
else {
62+
requests.add(TestCase.createTestCase(Request.aClass(clazz), arg));
63+
}
64+
}
65+
catch (ClassNotFoundException ignored) {
66+
requests.add(TestCase.createTestCase());
67+
}
68+
}
69+
}
70+
return requests;
71+
}
72+
73+
void runTestCases(List<TestCase> testCases) {
74+
results = new ArrayList<>();
75+
jUnitCore.addListener(new TestResultProvider(results));
76+
77+
testCases.forEach(this::runTestCase);
78+
}
79+
80+
private void runTestCase(TestCase testCase) {
81+
if (testCase.exists()) {
82+
if (!testCase.run(jUnitCore)) {
83+
oneFailure = true;
84+
}
85+
}
86+
else {
87+
results.add(createTestNotFoundResult(testCase.description()));
88+
oneFailure = true;
89+
}
90+
}
91+
92+
private TestResultDto createTestNotFoundResult(String testReference) {
93+
TestResultDto result = new TestResultDto();
94+
result.setSuccess(false);
95+
result.setNotFound(true);
96+
result.setTestReference(testReference);
97+
return result;
98+
}
99+
100+
private boolean generateResult() {
101+
String resultOutput = System.getProperty("codingame.junit-runner.output", DEFAULT_OUTPUT);
102+
String resultStr = new Gson().toJson(results);
103+
if (DEFAULT_OUTPUT.equals(resultOutput)) {
104+
realOut.println(resultStr);
105+
}
106+
else {
107+
try {
108+
FileUtils.writeStringToFile(new File(resultOutput), resultStr);
109+
}
110+
catch (IOException e) {
111+
realErr.println(e.getMessage());
112+
return false;
113+
}
114+
}
115+
return true;
116+
}
117+
118+
static class TestCase {
119+
120+
static TestCase createTestCase() {
121+
return new TestCase(null, null);
122+
}
123+
124+
static TestCase createTestCase(Request request, String description) {
125+
TestCase testCase = new TestCase(null, null);
126+
if (request != null) {
127+
Runner runner = request.getRunner();
128+
if (!(runner instanceof ErrorReportingRunner)) {
129+
testCase = new TestCase(request, description);
130+
}
131+
}
132+
return testCase;
133+
}
134+
135+
private final Request request;
136+
private final String description;
137+
138+
private TestCase(Request request, String description) {
139+
this.request = request;
140+
this.description = description;
141+
}
142+
143+
Request request() {
144+
return this.request;
145+
}
146+
147+
String description() {
148+
return this.description;
149+
}
150+
151+
boolean exists() {
152+
return request() != null;
153+
}
154+
155+
boolean run(final JUnitCore jUnitCore) {
156+
return jUnitCore.run(request).wasSuccessful();
157+
}
158+
}
159+
160+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package com.codingame.codemachine.runner.junit;
2+
3+
import com.codingame.codemachine.runner.junit.JUnitTest.TestCase;
4+
import org.junit.Before;
5+
import org.junit.Test;
6+
7+
import java.util.List;
8+
9+
import static org.assertj.core.api.Assertions.assertThat;
10+
11+
public class TestJunitTest {
12+
13+
private JUnitTest jUnitTest;
14+
15+
@Before
16+
public void setUp() {
17+
jUnitTest = new JUnitTest();
18+
}
19+
20+
@Test
21+
public void should_find_a_test_class() throws ClassNotFoundException {
22+
String className = "resources.simple.com.codingame.core.MyFirstTest";
23+
checkTestCase(className);
24+
}
25+
26+
@Test
27+
public void should_not_find_test_class_if_it_does_not_exist() throws ClassNotFoundException {
28+
String className = "unknown.ClassTest";
29+
List<TestCase> testCases = jUnitTest.findRequests(className);
30+
assertThat(testCases).hasSize(1);
31+
assertThat(testCases.get(0).exists()).isFalse();
32+
}
33+
34+
@Test
35+
public void should_find_a_test_method() {
36+
String className = "resources.simple.com.codingame.core.MyFirstTest";
37+
String methodName = "myFirstTest";
38+
checkTestCase(className, methodName);
39+
}
40+
41+
@Test
42+
public void should_find_many_test_methods() {
43+
String className = "resources.simple.com.codingame.core.MyFirstTest";
44+
String methodName0 = "myFirstTest";
45+
String methodName1 = "aSecondTest";
46+
List<TestCase> testCases =
47+
jUnitTest.findRequests(className + "#" + methodName0, className + "#" + methodName1);
48+
assertThat(testCases).hasSize(2);
49+
assertThat(testCases.get(0).exists()).isTrue();
50+
assertThat(testCases.get(0).description()).isEqualTo(className + "#" + methodName0);
51+
assertThat(testCases.get(1).exists()).isTrue();
52+
assertThat(testCases.get(1).description()).isEqualTo(className + "#" + methodName1);
53+
}
54+
55+
@Test
56+
public void should_find_many_test_methods_even_with_errors() {
57+
String className = "resources.simple.com.codingame.core.MyFirstTest";
58+
String methodName0 = "myFirstTest";
59+
String methodName1 = "unknown";
60+
List<TestCase> testCases =
61+
jUnitTest.findRequests(className + "#" + methodName0, className + "#" + methodName1);
62+
assertThat(testCases).hasSize(2);
63+
assertThat(testCases.get(0).exists()).isTrue();
64+
assertThat(testCases.get(1).exists()).isFalse();
65+
}
66+
67+
@Test
68+
public void should_find_a_test_method_regardless_of_runWith() {
69+
String className = "resources.run_with.io.vertx.blog.first.MyFirstVerticleTest";
70+
String methodName = "testMyApplication";
71+
checkTestCase(className, methodName);
72+
}
73+
74+
@Test
75+
public void does_not_work_with_parameterized_test_class() {
76+
String className = "resources.parameterized.com.codingame.core.FibonacciTest";
77+
String methodName = "test";
78+
List<TestCase> testCases = jUnitTest.findRequests(className + "#" + methodName);
79+
assertThat(testCases).hasSize(1);
80+
assertThat(testCases.get(0).exists()).isFalse();
81+
}
82+
83+
private void checkTestCase(String className) throws ClassNotFoundException {
84+
List<TestCase> testCases = jUnitTest.findRequests(className);
85+
assertThat(testCases).hasSize(1);
86+
87+
Class<?> clazz = Class.forName(className);
88+
int expectedTestCount = clazz.getDeclaredMethods().length;
89+
assertThat(testCases.get(0).exists()).isTrue();
90+
assertThat(testCases.get(0).description()).isEqualTo(className);
91+
int testCount = testCases.get(0).request().getRunner().testCount();
92+
assertThat(testCount).isEqualTo(expectedTestCount);
93+
}
94+
95+
private void checkTestCase(String className, String methodName) {
96+
List<TestCase> testCases = jUnitTest.findRequests(className + "#" + methodName);
97+
assertThat(testCases).hasSize(1);
98+
assertThat(testCases.get(0).exists()).isTrue();
99+
assertThat(testCases.get(0).description()).isEqualTo(className + "#" + methodName);
100+
int testCount = testCases.get(0).request().getRunner().testCount();
101+
assertThat(testCount).isEqualTo(1);
102+
}
103+
104+
@Test
105+
public void should_run_only_known_test_methods() {
106+
String className = "resources.simple.com.codingame.core.MyFirstTest";
107+
String methodName0 = "myFirstTest";
108+
String methodName1 = "unknown";
109+
110+
JUnitTest jUnitTest = new JUnitTest();
111+
List<TestCase> testCases = jUnitTest.findRequests(className + "#" + methodName0, className + "#" + methodName1);
112+
jUnitTest.runTestCases(testCases);
113+
114+
assertThat(jUnitTest.isOneFailure()).isTrue();
115+
}
116+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package resources.parameterized.com.codingame.core;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import org.junit.Test;
6+
import org.junit.runner.RunWith;
7+
import org.junit.runners.Parameterized;
8+
import org.junit.runners.Parameterized.Parameters;
9+
10+
import java.util.Arrays;
11+
12+
@RunWith(Parameterized.class)
13+
public class FibonacciTest {
14+
15+
@Parameters
16+
public static Iterable<Object[]> data() {
17+
return Arrays.asList(
18+
new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
19+
}
20+
21+
private int input;
22+
private int expected;
23+
24+
public FibonacciTest(int input, int expected) {
25+
this.input = input;
26+
this.expected = expected;
27+
}
28+
29+
@Test
30+
public void test() {
31+
assertEquals(expected, Fibonacci.compute(input));
32+
}
33+
}
34+
35+
class Fibonacci {
36+
static int compute(int n) {
37+
if (n <= 1) {
38+
return n;
39+
}
40+
return compute(n-1) + compute(n-2);
41+
}
42+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package resources.run_with.io.vertx.blog.first;
2+
3+
import io.vertx.core.AbstractVerticle;
4+
import io.vertx.core.Future;
5+
6+
public class MyFirstVerticle extends AbstractVerticle {
7+
@Override
8+
public void start(Future<Void> fut) {
9+
vertx
10+
.createHttpServer()
11+
.requestHandler(r -> {
12+
r.response().end("<h1>Hello from my first " +
13+
"Vert.x 3 application</h1>");
14+
})
15+
.listen(8080, result -> {
16+
if (result.succeeded()) {
17+
fut.complete();
18+
} else {
19+
fut.fail(result.cause());
20+
}
21+
});
22+
}
23+
}

0 commit comments

Comments
 (0)