@Test
  public void a_test_result_can_be_defined_for_a_step() throws InterruptedException {
    TestStep step = new TestStep("a narrative description");
    step.setResult(TestResult.SUCCESS);

    assertThat(step.getResult(), is(TestResult.SUCCESS));
  }
  @Test
  public void when_a_step_fails_the_error_message_can_be_recorded() throws IOException {
    TestStep step = new TestStep("a narrative description");

    step.setResult(TestResult.FAILURE);
    step.failedWith(new Exception("Oh nose!"));
    assertThat(step.getErrorMessage(), containsString("Oh nose!"));
  }
  @Test
  public void the_short_error_message_should_remove_double_quotes() throws IOException {
    TestStep step = new TestStep("a narrative description");

    step.setResult(TestResult.FAILURE);
    Throwable e = new IllegalStateException("Original error");
    step.failedWith(new Exception("Oh nose", e));
    assertThat(step.getShortErrorMessage(), is("Original error"));
  }
  @Test
  public void the_short_error_message_should_only_include_the_first_line() throws IOException {
    TestStep step = new TestStep("a narrative description");

    step.setResult(TestResult.FAILURE);
    Throwable e = new IllegalStateException("Original error\nwith lots of messy details");
    step.failedWith(new Exception("Oh nose", e));
    assertThat(step.getShortErrorMessage(), is("Original error"));
  }
  @Test
  public void when_a_step_fails_with_a_cause_the_original_message_is_used() throws IOException {
    TestStep step = new TestStep("a narrative description");

    step.setResult(TestResult.FAILURE);
    Throwable e = new IllegalStateException("Original error");
    step.failedWith(new Exception("Oh nose", e));
    assertThat(step.getErrorMessage(), containsString("Original error"));
  }
  @Test
  public void when_a_step_fails_the_stack_trace_is_also_recorded() throws IOException {
    TestStep step = new TestStep("a narrative description");

    step.setResult(TestResult.FAILURE);
    Throwable e = new IllegalStateException();
    step.failedWith(new Exception("Oh nose", e));
    assertThat(step.getException().getStackTrace(), is(notNullValue()));
  }
  @Test
  public void the_short_error_message_should_replace_double_quotes_with_single_quotes()
      throws IOException {
    TestStep step = new TestStep("a narrative description");

    step.setResult(TestResult.FAILURE);
    Throwable e = new IllegalStateException("Original \"error\"\nwith lots of messy details");
    step.failedWith(new Exception("Oh nose", e));
    assertThat(step.getShortErrorMessage(), is("Original 'error'"));
  }
  @Test
  public void a_pending_test_step_with_successful_child_steps_is_still_pending()
      throws InterruptedException {
    TestStep step = new TestStep("a narrative description");
    step.setResult(TestResult.PENDING);
    step.addChildStep(successfulTestStepCalled("child step 1"));
    step.addChildStep(successfulTestStepCalled("child step 2"));
    step.addChildStep(successfulTestStepCalled("child step 3"));

    assertThat(step.getResult(), is(TestResult.PENDING));
  }
  @Test
  public void a_skipped_test_step_with_successful_child_steps_is_still_ignored()
      throws InterruptedException {
    TestStep step = new TestStep("a narrative description");
    step.setResult(TestResult.SKIPPED);
    step.addChildStep(successfulTestStepCalled("child step 1"));
    step.addChildStep(successfulTestStepCalled("child step 2"));
    step.addChildStep(successfulTestStepCalled("child step 3"));

    assertThat(step.getResult(), is(TestResult.SKIPPED));
  }
 private TestStep successfulTestStepCalled(String stepName) {
   TestStep step = new TestStep(stepName);
   step.setResult(TestResult.SUCCESS);
   return step;
 }