Просмотр исходного кода

Mark all but first test @Ignore in hello-world

- in base build script, filter out @Ignores so that maintainers can run
  the full test suites.
- increase the verbosity of test logging to aide in seeing progress as
  tests are un@Ignored and solved.
- revamped GETTING_STARTED.md to reflect new output.  It is now a
  complete guide from start to finish with calls-to-action at the end of
  the instructions.
John S. Ryan 10 лет назад
Родитель
Сommit
869781b9c4

+ 16
- 4
exercises/build.gradle Просмотреть файл

18
     project["compileStarterSourceJava"].doFirst { compileTask ->
18
     project["compileStarterSourceJava"].doFirst { compileTask ->
19
       println "  (source = " + compileTask.source.asPath + ")"
19
       println "  (source = " + compileTask.source.asPath + ")"
20
     }
20
     }
21
+
22
+    // In lieu of being able to disable @Ignore in JUnit tests, we filter
23
+    // those annotations, placing the edited tests in the path named here.
24
+    test {
25
+      java.srcDirs = ["build/gen/test/java"]
26
+    }
27
+    project["compileTestJava"].doFirst { compileTask ->
28
+      println "  (source = " + compileTask.source.asPath + ")"
29
+    }
21
   }
30
   }
22
 
31
 
23
-  task fullTest(type: Test) {
24
-    group = LifecycleBasePlugin.VERIFICATION_GROUP
25
-    description = "Runs tests without exclusions."
32
+  task copyTestsFilteringIgnores(type: Copy) {
33
+    from "src/test/java"
34
+    into "build/gen/test/java"
35
+    filter { line ->
36
+      line.contains("@Ignore") ? null : line
37
+    }
26
   }
38
   }
27
 
39
 
28
-  check.dependsOn(fullTest)
40
+  test.dependsOn(copyTestsFilteringIgnores)
29
 }
41
 }

+ 0
- 6
exercises/grade-school/build.gradle Просмотреть файл

10
   testCompile "junit:junit:4.10"
10
   testCompile "junit:junit:4.10"
11
   testCompile "org.assertj:assertj-core:3.2.0"
11
   testCompile "org.assertj:assertj-core:3.2.0"
12
 }
12
 }
13
-
14
-test {
15
-    useJUnit {
16
-        excludeCategories 'io.exercism.xjava.NotReady'
17
-    }
18
-}

+ 0
- 8
exercises/grade-school/src/example/java/io/exercism/xjava/NotReady.java Просмотреть файл

1
-package io.exercism.xjava;
2
-
3
-/**
4
- * Marker interface used to exclude tests as you work
5
- * through each exercise.
6
- */
7
-public interface NotReady {
8
-}

+ 0
- 8
exercises/grade-school/src/test/java/SchoolTest.java Просмотреть файл

1
 import static org.assertj.core.api.Assertions.assertThat;
1
 import static org.assertj.core.api.Assertions.assertThat;
2
 
2
 
3
-import io.exercism.xjava.NotReady;
4
-import org.junit.experimental.categories.Category;
5
 import org.junit.Test;
3
 import org.junit.Test;
6
 
4
 
7
 import java.util.Arrays;
5
 import java.util.Arrays;
18
   }
16
   }
19
 
17
 
20
   @Test
18
   @Test
21
-  @Category(NotReady.class)
22
   public void addsStudents() {
19
   public void addsStudents() {
23
     school.add("Aimee", 2);
20
     school.add("Aimee", 2);
24
     assertThat(school.db().get(2)).contains("Aimee");
21
     assertThat(school.db().get(2)).contains("Aimee");
25
   }
22
   }
26
 
23
 
27
   @Test
24
   @Test
28
-  @Category(NotReady.class)
29
   public void addsMoreStudentsInSameGrade() {
25
   public void addsMoreStudentsInSameGrade() {
30
     final int grade = 2;
26
     final int grade = 2;
31
     school.add("James", grade);
27
     school.add("James", grade);
36
   }
32
   }
37
 
33
 
38
   @Test
34
   @Test
39
-  @Category(NotReady.class)
40
   public void addsStudentsInMultipleGrades() {
35
   public void addsStudentsInMultipleGrades() {
41
     school.add("Chelsea", 3);
36
     school.add("Chelsea", 3);
42
     school.add("Logan", 7);
37
     school.add("Logan", 7);
47
   }
42
   }
48
 
43
 
49
   @Test
44
   @Test
50
-  @Category(NotReady.class)
51
   public void getsStudentsInAGrade() {
45
   public void getsStudentsInAGrade() {
52
     school.add("Franklin", 5);
46
     school.add("Franklin", 5);
53
     school.add("Bradley", 5);
47
     school.add("Bradley", 5);
56
   }
50
   }
57
 
51
 
58
   @Test
52
   @Test
59
-  @Category(NotReady.class)
60
   public void getsStudentsInEmptyGrade() {
53
   public void getsStudentsInEmptyGrade() {
61
     assertThat(school.grade(1)).isEmpty();
54
     assertThat(school.grade(1)).isEmpty();
62
   }
55
   }
63
 
56
 
64
   @Test
57
   @Test
65
-  @Category(NotReady.class)
66
   public void sortsSchool() {
58
   public void sortsSchool() {
67
     school.add("Jennifer", 4);
59
     school.add("Jennifer", 4);
68
     school.add("Kareem", 6);
60
     school.add("Kareem", 6);

+ 489
- 69
exercises/hello-world/GETTING_STARTED.md Просмотреть файл

1
-# Getting Started
1
+NOTE: You can also view the HTML version of this file here:
2
+https://github.com/exercism/xjava/blob/master/exercises/hello-world/GETTING_STARTED.md
2
 
3
 
3
-These exercises lean on Test-Driven Development (TDD), but they're not an exact match.
4
+* [Solving "Hello, World!"](#solving-hello-world)
5
+ * [Reading Gradle output](#reading-gradle-output)
6
+ * [Fixing the first failing test](#fixing-the-first-failing-test)
7
+ * [Enabling and fixing the second test](#enabling-and-fixing-the-second-test)
8
+ * [Enabling the last test](#enabling-the-last-test)
9
+ * [Refactoring](#refactoring)
10
+* [Submitting your first iteration](#submitting-your-first-iteration)
11
+* [Next Steps](#next-steps)
12
+ * [Review (and comment on) others' submissions to this exercise](#review-and-comment-on-others-submissions-to-this-exercise)
13
+ * [Extend an exercise](#extend-an-exercise)
4
 
14
 
5
-The following steps assume that you are in the base directory of the exercise.
15
+----
6
 
16
 
7
-You must have `gradle` installed.
17
+# Solving "Hello, World!"
8
 
18
 
9
-## Step 1
19
+Welcome to the first exercise on the Java track!
10
 
20
 
11
-Run the test suite. It's written using the JUnit framework, and can be run with gradle:
21
+This is a step-by-step guide to solving this exercise.
12
 
22
 
13
-```sh
14
-$ gradle test
15
-```
23
+Each exercise comes with a set of tests.  The first pass through the
24
+exercise is about getting all of the tests to pass, one at a time.
16
 
25
 
17
-This will fail, complaining that there is no method called `hello` for the `HelloWorld` class.
26
+If you have not installed the Java Development Kit and Gradle, you must do
27
+so now.  For help with this, see: http://exercism.io/languages/java/installing
18
 
28
 
19
-To fix the error, open `src/main/java/HelloWorld.java` and add a `hello` method that returns a `String`.
20
-The method can return an empty string `""` for now:
29
+----
21
 
30
 
22
-```java
23
-public class HelloWorld {
24
-    public static String hello() {
25
-        return "";
26
-    }
27
-}
28
-```
31
+This guide picks-up where [Running the Tests (in Java)](http://exercism.io/languages/java/tests)
32
+left off.  If you haven't reviewed those instructions, do so now.
29
 
33
 
30
-## Step 2
34
+The following instructions work equally well on Windows, Mac OS X and Linux.
31
 
35
 
32
-Run the tests again. It will give you a new error, since now the method exists, but the tests expect the
33
-method to accept one argument as input, a name.
36
+## Reading Gradle output
34
 
37
 
35
-The errors will look something like:
38
+Use Gradle to run the tests:
36
 
39
 
37
 ```
40
 ```
38
 $ gradle test
41
 $ gradle test
42
+```
43
+
44
+This command does a lot and displays a bunch of stuff.  Let's break it down...
45
+
46
+```
39
 :compileJava
47
 :compileJava
40
 :processResources UP-TO-DATE
48
 :processResources UP-TO-DATE
41
 :classes
49
 :classes
50
+```
51
+
52
+Each line that begins with a colon (like `:compileJava`) is Gradle telling
53
+us that it's starting that task.  The first three tasks are about compiling
54
+the source code of our *solution*. We've done you a favor and included just
55
+enough code for the solution that it compiles.
56
+
57
+When a task is successful, it generally does not output anything.  This is
58
+why `:compileJava` and `:classes` do not produce any additional output.
59
+`:processResources` reports that it had nothing to do.
60
+
61
+So far, so good...
62
+
63
+The next three tasks are about compiling source code of the *tests*.
64
+
65
+```
42
 :compileTestJava
66
 :compileTestJava
43
-/exercism/exercises/java/hello-world/src/test/java/HelloWorldTest.java:9: error: method hello in class HelloWorld cannot be applied to given types;
44
-        assertEquals("Hello, World!", HelloWorld.hello(""));
45
-                                                ^
46
-  required: no arguments
47
-  found: String
48
-  reason: actual and formal argument lists differ in length
67
+:processTestResources UP-TO-DATE
68
+:testClasses
69
+```
49
 
70
 
50
-  ...
71
+... with both sets of source code successfully compiled, Gradle turns to
72
+running the task you asked it to: executing the tests against the solution.
51
 
73
 
52
-4 errors
53
-:compileTestJava FAILED
74
+```
75
+:test
76
+
77
+HelloWorldTest > helloNoName FAILED
78
+    java.lang.AssertionError: expected:<Hello, World!> but was:<null>
79
+        at org.junit.Assert.fail(Assert.java:93)
80
+        at org.junit.Assert.failNotEquals(Assert.java:647)
81
+        at org.junit.Assert.assertEquals(Assert.java:128)
82
+        at org.junit.Assert.assertEquals(Assert.java:147)
83
+        at HelloWorldTest.helloNoName(HelloWorldTest.java:10)
84
+
85
+HelloWorldTest > helloSampleName SKIPPED
86
+
87
+HelloWorldTest > helloAnotherSampleName SKIPPED
88
+
89
+3 tests completed, 1 failed, 2 skipped
90
+:test FAILED
54
 
91
 
55
 FAILURE: Build failed with an exception.
92
 FAILURE: Build failed with an exception.
56
 
93
 
57
 * What went wrong:
94
 * What went wrong:
58
-Execution failed for task ':compileTestJava'.
59
-> Compilation failed; see the compiler error output for details.
95
+Execution failed for task ':test'.
96
+> There were failing tests. See the report at: file:///Users/jtigger/projects/exercism/xjava/build/exercism/java/hello-world/build/reports/tests/index.html
97
+
98
+* Try:
99
+Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
100
+
101
+BUILD FAILED
102
+
103
+Total time: 6.716 secs
104
+```
105
+
106
+Seeing the word "fail" TEN TIMES might give you the impression you've done
107
+something horribly wrong.  You haven't.  It's a whole lot of noise over
108
+a single test not passing.
109
+
110
+Let's focus in on the important bits:
111
+
112
+```
113
+HelloWorldTest > helloNoName FAILED
114
+    java.lang.AssertionError: expected:<Hello, World!> but was:<null>
115
+```
116
+
117
+...is read: "Within the test class named `HelloWorldTest`, the test method
118
+`helloNoName` did not pass because the solution did not satisfy an
119
+assertion.  Apparently, we expected to see the string 'Hello, World!' but
120
+the value `null` was returned instead.
121
+
122
+The last line of the stack trace tells us exactly where this unsatisfied
123
+assertion lives:
124
+
60
 ```
125
 ```
126
+        at HelloWorldTest.helloNoName(HelloWorldTest.java:10)
127
+```
128
+
129
+Looks like the crime was discovered on line 10 in the test file.
130
+
131
+Knowing these two facts,
132
+
133
+1. the return value was not what was expected, and
134
+2. the failure was on line 10 of the test,
135
+ 
136
+we can turn this failure into success.
61
 
137
 
62
-### Fixing the Error
63
 
138
 
64
-To fix it, open `src/main/java/HelloWorld.java` and add a `name` to the method the signature:
139
+
140
+## Fixing the first failing test
141
+
142
+In your favorite text editor, open `src/test/java/HelloWorldTest.java`
143
+and go to line 10.
65
 
144
 
66
 ```java
145
 ```java
67
-public class HelloWorld {
68
-    public static String hello(String name) {
69
-        return "";
70
-    }
71
-}
146
+assertEquals("Hello, World!", HelloWorld.hello(""));
72
 ```
147
 ```
73
 
148
 
74
-Now the `hello` method accepts a `name` as an input.
149
+The test is expecting that `hello()`, when given an empty string (`""`),
150
+returns "Hello, World!".  Instead, `hello()` is returning `null`.
151
+Let's fix that.
75
 
152
 
76
-### Understanding Test Failures
153
+Open `src/main/java/HelloWorld.java`.
77
 
154
 
78
-Test failures will either be compilation errors or test failures. So far, we've been dealing with compilation
79
-errors. Once our test and main code successful compile, `gradle` will run the actual test suite.
155
+```java
156
+public class HelloWorld {
157
+  public static String hello(String name) {
158
+    return null;
159
+  }
160
+}
161
+```
80
 
162
 
81
-## Step 3
163
+Let's change that to return the expected string:
82
 
164
 
83
-Run the tests again. You'll notice that the gradle output passes the `:compileTestJava` phase and fails
84
-at the `:test` phase.
165
+```java
166
+public class HelloWorld {
167
+  public static String hello(String name) {
168
+    return "Hello, World!";
169
+  }
170
+}
171
+```
85
 
172
 
86
-The errors will look something like:
173
+Save the file and run the tests again:
87
 
174
 
88
 ```
175
 ```
89
 $ gradle test
176
 $ gradle test
95
 :testClasses
182
 :testClasses
96
 :test
183
 :test
97
 
184
 
98
-HelloWorldTest > helloNoName FAILED
99
-    org.junit.ComparisonFailure at HelloWorldTest.java:9
185
+HelloWorldTest > helloAnotherSampleName SKIPPED
186
+
187
+HelloWorldTest > helloNoName PASSED
188
+
189
+HelloWorldTest > helloSampleName SKIPPED
190
+
191
+BUILD SUCCESSFUL
192
+
193
+Total time: 4.523 secs
194
+```
195
+
196
+"BUILD SUCCESSFUL"!  Woohoo! :)  You can see that `helloNoName()` test is
197
+now passing.
198
+
199
+With one win under our belt, we can turn our focus to some other messages
200
+that we've been ignoring: the lines ending in "`SKIPPED`".
201
+
202
+Each test suite contains a series of tests, all of which have been marked
203
+to be skipped/ignored except the first one.  We did this to help you focus
204
+on getting one test running at a time.
100
 
205
 
206
+Let's tackle the next test...
207
+
208
+
209
+
210
+## Enabling and fixing the second test
211
+
212
+Right now, that second test is being skipped/ignored.  Let's enable it.
213
+
214
+(Re)open `src/test/java/HelloWorldTest.java` and find the second test:
215
+
216
+```java
101
 ...
217
 ...
218
+@Test
219
+@Ignore
220
+public void helloSampleName() {
221
+  assertEquals("Hello, Alice!", HelloWorld.hello("Alice"));
222
+}
223
+...
224
+```
102
 
225
 
103
-3 tests completed, 3 failed
104
-:test FAILED
226
+When the JUnit test runner sees that `@Ignore` annotation on the test
227
+method, it knows to skip over that test.  Remove that line:
228
+
229
+```java
230
+...
231
+@Test
232
+public void helloSampleName() {
233
+  assertEquals("Hello, Alice!", HelloWorld.hello("Alice"));
234
+}
235
+...
236
+```
237
+
238
+Now, when you run the tests, both tests run:
239
+
240
+```sh
241
+$ gradle test
242
+...
243
+:test
244
+
245
+HelloWorldTest > helloNoName PASSED
246
+
247
+HelloWorldTest > helloSampleName FAILED
248
+    org.junit.ComparisonFailure: expected:<Hello, [Alice]!> but was:<Hello, [World]!>
249
+        at org.junit.Assert.assertEquals(Assert.java:125)
250
+        at org.junit.Assert.assertEquals(Assert.java:147)
251
+        at HelloWorldTest.helloSampleName(HelloWorldTest.java:16)
252
+
253
+HelloWorldTest > helloAnotherSampleName SKIPPED
254
+
255
+3 tests completed, 1 failed, 1 skipped
256
+...
105
 ```
257
 ```
106
 
258
 
107
-These are actual test failures. It means that both our main and test java code is running but the test is
108
-expecting one outcome, but getting another.
259
+The first test, `helloNoName()` continues to pass.  We see that
260
+`helloSampleName` -- the test we just un-`@Ignore`'d -- is now running and
261
+failing.  Yay, failing test!  In fact, the "failure" message is just
262
+describing the difference between what the program does now and what it
263
+should do for us to call it "done."
109
 
264
 
110
-Open `src/test/java/HelloWorldTest.java` and go to line 9.
265
+Right now, we've hardcoded the greeting.  Enabling this second test has
266
+unleashed a new expectation: that our program incorporate a name given
267
+into that greeting.  When given the name "`Alice`", that's who should be
268
+greeted instead of "`World`".
269
+
270
+(Re)open `src/main/java/HelloWorld.java`.
111
 
271
 
112
 ```java
272
 ```java
113
-assertEquals("Hello, World!", HelloWorld.hello(""));
273
+public class HelloWorld {
274
+  public static String hello(String name) {
275
+    return "Hello, World!";
276
+  }
277
+}
278
+```
279
+
280
+While `hello()` does accept a reference to a string named `name`, it is not
281
+using it in the output.  Let's change that:
282
+
283
+
284
+```java
285
+public class HelloWorld {
286
+  public static String hello(String name) {
287
+    return "Hello, " + name + "!";
288
+  }
289
+}
290
+```
291
+
292
+... and rerun the tests ...
293
+
294
+```
295
+$ gradle test
296
+:test
297
+
298
+HelloWorldTest > helloAnotherSampleName SKIPPED
299
+
300
+HelloWorldTest > helloNoName FAILED
301
+    org.junit.ComparisonFailure: expected:<Hello, [World]!> but was:<Hello, []!>
302
+        at org.junit.Assert.assertEquals(Assert.java:125)
303
+        at org.junit.Assert.assertEquals(Assert.java:147)
304
+        at HelloWorldTest.helloNoName(HelloWorldTest.java:10)
305
+
306
+HelloWorldTest > helloSampleName PASSED
307
+
308
+3 tests completed, 1 failed, 1 skipped
114
 ```
309
 ```
115
 
310
 
116
-The test is expecting that `hello` returns "Hello, World!", when given an empty string (`""`) as input.
117
-The easiest way to make the test pass is to return `"Hello, World!"` instead of `"".
311
+Wait... didn't we just fix the test?  Why is it failing?  Take a closer look...
118
 
312
 
313
+In fact, `helloSampleName()` *is* passing.  It's just that at the same time,
314
+we just inadvertently broke that first test: `helloNoName()`.
315
+
316
+This is one tiny example of the benefit of maintaining a test suite: if we
317
+use them to drive out our code, the second we break the program the tests
318
+say so.  Since we saw them passing just *before* our latest change,
319
+whatever we *just* did most likely cause that regression.
320
+
321
+Our latest change was making the greeting dependent on the name given. Our
322
+first test expects that if either a blank string or null are given as the
323
+name, then "`World`" should be substituted in.  Let's implement that.
324
+
325
+`src/main/java/HelloWorld.java`:
119
 ```java
326
 ```java
120
 public class HelloWorld {
327
 public class HelloWorld {
121
-    public static String hello(String name) {
122
-        return "Hello, World!";
328
+  public static String hello(String name) {
329
+    if(name == null || "".equals(name)) {
330
+      name = "World";
123
     }
331
     }
332
+    return "Hello, " + name + "!";
333
+  }
124
 }
334
 }
125
 ```
335
 ```
126
 
336
 
127
-## Wash, Rinse, Repeat
337
+... and re-run the tests ...
128
 
338
 
129
-Run the tests again.
339
+```
340
+$ gradle test
341
+...
342
+:test
130
 
343
 
131
-If it fails you're going to need to read the error message carefully to figure out what went wrong, fix the problem
132
-in the main code, and then try again until all the tests pass.
344
+HelloWorldTest > helloNoName PASSED
345
+
346
+HelloWorldTest > helloSampleName PASSED
347
+
348
+HelloWorldTest > helloAnotherSampleName SKIPPED
349
+
350
+BUILD SUCCESSFUL
351
+
352
+Total time: 4.804 secs
353
+```
354
+
355
+Excellent!  We're now (at least) two-thirds the way done.  Just one more
356
+test to go...
357
+
358
+
359
+
360
+## Enabling the last test
361
+
362
+(Re)open `src/test/java/HelloWorldTest.java` and find the last test:
363
+
364
+```java
365
+...
366
+@Test
367
+@Ignore
368
+public void helloAnotherSampleName() {
369
+    assertEquals("Hello, Bob!", HelloWorld.hello("Bob"));
370
+}
371
+...
372
+```
373
+
374
+... and remove it's `@Ignore` to enable it ...
375
+
376
+```java
377
+...
378
+@Test
379
+public void helloAnotherSampleName() {
380
+    assertEquals("Hello, Bob!", HelloWorld.hello("Bob"));
381
+}
382
+...
383
+```
384
+
385
+... and re-run the tests ...
133
 
386
 
134
 ```
387
 ```
135
 $ gradle test
388
 $ gradle test
136
-:compileJava
389
+:compileJava UP-TO-DATE
137
 :processResources UP-TO-DATE
390
 :processResources UP-TO-DATE
138
-:classes
391
+:classes UP-TO-DATE
139
 :compileTestJava
392
 :compileTestJava
140
 :processTestResources UP-TO-DATE
393
 :processTestResources UP-TO-DATE
141
 :testClasses
394
 :testClasses
142
 :test
395
 :test
143
 
396
 
397
+HelloWorldTest > helloNoName PASSED
398
+
399
+HelloWorldTest > helloSampleName PASSED
400
+
401
+HelloWorldTest > helloAnotherSampleName PASSED
402
+
144
 BUILD SUCCESSFUL
403
 BUILD SUCCESSFUL
404
+
405
+Total time: 6.953 secs
145
 ```
406
 ```
146
 
407
 
147
-## Submit
408
+Oh, hello!  Turns out, the solution we put into place didn't just apply for
409
+"`Alice`" but "`Bob`" equally well.  In this case, the test succeeded with
410
+no additional code on our part.
411
+
412
+
413
+
414
+## Refactoring
415
+
416
+Now that you've got all the tests passing, you might consider whether
417
+the code is in the most readable/maintainable/efficient shape.  What makes
418
+for "good" design of software is a big topic.  The pursuit of it underlies
419
+much of what makes up the more valuable conversations on Exercism.
148
 
420
 
149
-When everything is passing, you can submit your code with the following command:
421
+For now, let's just take a quick review of our solution and see if there's
422
+any part of it we'd like to refactor.  Refactoring is changing the the way
423
+a bit of code reads without changing what it does.
424
+
425
+Right now, the details of detecting whether the caller of `hello()` has
426
+given a name or not (i.e. `name` is either `null` or an empty string) is
427
+sitting right next to the core responsibility of the method: to produce a
428
+personalized greeting.
429
+
430
+```java
431
+public class HelloWorld {
432
+  public static String hello(String name) {
433
+    if(name == null || "".equals(name)) {
434
+      name = "World";
435
+    }
436
+    return "Hello, " + name + "!";
437
+  }
438
+}
439
+```
440
+
441
+How would things read if we extracted those details into a separate method
442
+and at the same time, replaced the `if` with a ternary expression?
443
+
444
+```java
445
+public class HelloWorld {
446
+
447
+  public static String hello(String name) {
448
+    String whom = isBlank(name) ? "World" : name;
449
+    return "Hello, " + whom + "!";
450
+  }
451
+
452
+  private static boolean isBlank(String string) {
453
+    return string == null || "".equals(string);
454
+  }
455
+}
456
+```
457
+
458
+By extracting that logic into the `isBlank()` method, we've added a little
459
+abstraction to our program -- it's not as literal as it was before.  Yet,
460
+it allows us to defer *needing* to understand *how* "blankness" is
461
+detected.  If we can assume that `isBlank()` just works, we don't have to
462
+downshift in our head to those details.  Instead, we can remain at the same
463
+level of thinking: to whom are we greeting?
464
+
465
+The ternary operator allowed us to express that choice in a more compact
466
+form.  Less to read without losing the intent.
467
+
468
+Finally, we introduced another variable: `whom`.  Doing so gives a name to
469
+the output of the ternary expression.  We certainly could have continued
470
+to reuse `name`, but by introducing a second `String` to hold the
471
+calculated value this keeps crisp the two ideas: `name` is what's given
472
+and `whom` is what's been determined.
473
+
474
+We made a bunch of changes, let's make sure we didn't break the program!
475
+
476
+```
477
+$ gradle test
478
+...
479
+HelloWorldTest > helloNoName PASSED
480
+
481
+HelloWorldTest > helloSampleName PASSED
482
+
483
+HelloWorldTest > helloAnotherSampleName PASSED
484
+...
485
+```
486
+
487
+This illustrates another benefit of writing tests: you can make significant
488
+changes to the structure of the program and very quickly restore your
489
+confidence that the program still works.  These tests are a far cry from a
490
+"proof" of correctness, but well-written tests do a much better job of
491
+(very quickly) giving us evidence that it is.  Without them, we manually
492
+run the program with different inputs and/or inspecting the code
493
+line-by-line -- time-consuming and error prone.
494
+
495
+
496
+
497
+# Submitting your first iteration
498
+
499
+With a working solution that we've reviewed, we're ready to submit it to
500
+exercism.io.
150
 
501
 
151
 ```
502
 ```
152
 $ exercism submit src/main/java/HelloWorld.java
503
 $ exercism submit src/main/java/HelloWorld.java
154
 
505
 
155
 
506
 
156
 
507
 
508
+# Next Steps
509
+
510
+From here, there are a number of paths you can take.
511
+
512
+
513
+## Move on to the next exercise
514
+
515
+There are many more exercises you can practice with.  Grab the next one!
516
+
517
+```
518
+$ exercism fetch java
519
+```
520
+
521
+
522
+## Review (and comment on) others' submissions to this exercise
523
+
524
+The heart of Exercism are the conversations about coding
525
+practices.  It's definitely fun to practice, but engaging with others
526
+both in their attempts and your own is how you get feedback.  That feedback
527
+can help point out what you're doing well and where you might need to
528
+improve.
529
+
530
+Some submissions will be nearly identical to yours; others will be
531
+completely different.  Seeing both kinds can be instructive and interesting.
532
+
533
+Note that you can only view submissions of others for exercises you have
534
+completed yourself.  This enriches the experience of reading others' code
535
+because you'll have your own experience of trying to solve the problem.
536
+
537
+Here's an up-to-date list of submissions on the Java track:
538
+
539
+http://exercism.io/tracks/java/exercises
540
+
541
+
542
+
543
+## Submit another iteration
544
+
545
+You are also encouraged to consider additional "requirements" on a given
546
+exercise.
547
+
548
+For example, you could add a test or two that requires that the greeting
549
+use the capitalized form on the person's name, regardless of the case they
550
+used.
551
+
552
+In that situation, you'd write a test to set-up that new expectation and
553
+then implement that in the code (the same process we just went through
554
+together, above).
555
+
556
+
557
+
558
+## Contribute to Exercism
559
+
560
+The entire of Exercism is Open Source and is the labor of love for over
561
+100 maintainers and many more contributors.
562
+
563
+A starting point to jumping in can be found here:
564
+
565
+https://github.com/exercism/x-common/blob/master/CONTRIBUTING.md
566
+
567
+
568
+----
569
+
570
+Regardless of what you decide to do next, we sincerely hope you learn
571
+and enjoy being part of this community.  If at any time you need assistance
572
+do not hesitate to ask for help:
573
+
574
+http://exercism.io/languages/java/help
575
+
576
+Cheers!

+ 6
- 0
exercises/hello-world/build.gradle Просмотреть файл

10
   testCompile "junit:junit:4.10"
10
   testCompile "junit:junit:4.10"
11
 }
11
 }
12
 
12
 
13
+test {
14
+  testLogging {
15
+    exceptionFormat = 'full'
16
+    events = ["passed", "failed", "skipped"]
17
+  }
18
+}

+ 3
- 0
exercises/hello-world/src/main/java/HelloWorld.java Просмотреть файл

1
 public class HelloWorld {
1
 public class HelloWorld {
2
+	public static String hello(String name) {
3
+      return null;
4
+	}
2
 }
5
 }

+ 3
- 0
exercises/hello-world/src/test/java/HelloWorldTest.java Просмотреть файл

1
 import org.junit.Test;
1
 import org.junit.Test;
2
+import org.junit.Ignore;
2
 
3
 
3
 import static org.junit.Assert.assertEquals;
4
 import static org.junit.Assert.assertEquals;
4
 
5
 
11
     }
12
     }
12
 
13
 
13
     @Test
14
     @Test
15
+    @Ignore
14
     public void helloSampleName() {
16
     public void helloSampleName() {
15
         assertEquals("Hello, Alice!", HelloWorld.hello("Alice"));
17
         assertEquals("Hello, Alice!", HelloWorld.hello("Alice"));
16
     }
18
     }
17
 
19
 
18
     @Test
20
     @Test
21
+    @Ignore
19
     public void helloAnotherSampleName() {
22
     public void helloAnotherSampleName() {
20
         assertEquals("Hello, Bob!", HelloWorld.hello("Bob"));
23
         assertEquals("Hello, Bob!", HelloWorld.hello("Bob"));
21
     }
24
     }