Uploaded image for project: 'Magnolia'
  1. Magnolia
  2. MAGNOLIA-6092

Hamcrest UtilMatchers: a pattern for asserting an exception is thrown

XMLWordPrintable

    • Icon: New Feature New Feature
    • Resolution: Fixed
    • Icon: Neutral Neutral
    • 5.4
    • None
    • testing
    • None

      In our current unit tests, we use a mixture of 2 patterns to assert the certain code throws certain exception:

          @Test(expected = IllegalArgumentException.class)
          public void testGetTitleThrowsException() {
              new MetaData(root).getTitle();
          }
      
          @Test
          public void testGetTitleThrowsException() {
              try {
                new MetaData(root).getTitle();
                fail("should have failed");
              } catch (Throwable t) {
                // various assertions on t, possibly using info.magnolia.test.hamcrest.UtilMatchers 
              }
          }
      

      The former is concise, but leaves no place for signaling the intent of the test, and provides no way to check the actual exception; it's good enough in some cases, but in others, we really want to make sure we're getting the precise exception we think we're getting.

      The latter is much more precise, but is a tad verbose, maybe a bit difficult to read, and can be error prone (it's easy to forget the call to fail(), for example)

      I propose the following, implemented using a new matcher:

      
      import static info.magnolia.test.hamcrest.UtilMatchers.*;
      import static org.junit.Assert.*;
      import info.magnolia.test.hamcrest.Execution;
      
      ...
      
          @Test
          public void throwMatcherSampleUsage() {
              assertThat(new Execution(){
                  public void evaluate() throws Exception {
                      // do something that fails, such as
                      System.out.println(1/0);
                  }
              }, throwMatcher(isExceptionWithMatchingMessage(ArithmeticException.class, "/ by zero")));
          }
      

      or, slightly differently:

          @Test
          public void throwMatcherSampleUsage() {
              final Execution shouldFail = new Execution() {
                  @Override
                  public void evaluate() throws Exception {
                      // do something that fails, such as
                      System.out.println(1 / 0);
                  }
              };
              assertThat(shouldFail, throwMatcher(isExceptionWithMatchingMessage(ArithmeticException.class, "/ by zero")));
          }
      

      Additionally, we can even have the same principle to assert that a piece of code does not throw any exception:

       assertThat(new Execution() {
                  @Override
                  public void evaluate() throws Exception {
                      // yay
                  }
              }, noExceptionThrown());
      

      And here's a sample of how it'd look like if we used Java 8's lambdas:

              assertThat(() -> System.out.print(1 / 0), throwsException(isExceptionWithMatchingMessage(ArithmeticException.class, "/ by zero")));
      

        Acceptance criteria

              gjoseph Magnolia International
              gjoseph Magnolia International
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

                Created:
                Updated:
                Resolved: