DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Coding
  3. Java
  4. JUnit: Custom ExpectedException Rules…Rule!

JUnit: Custom ExpectedException Rules…Rule!

Alex Ruiz user avatar by
Alex Ruiz
·
Sep. 17, 10 · Interview
Like (0)
Save
Tweet
Share
12.78K Views

Join the DZone community and get the full member experience.

Join For Free

I’ve been using JUnit 4.7′s ExpectedException rule for some time now and I love it! IMHO, it combines the best of the old JUnit 3.x pattern for verifying expected exceptions and the expected attribute of JUnit 4′s @Test annotation, without their downsides. Although this is nothing new, I’ll explain them briefly:

The old JUnit 3.x pattern for verifying expected exceptions looks like this:

@Test 
public void shouldThrowNpeIfArgumentIsNull() {
  encoder.selectEncoding("Ewokeese");
  try {
    encoder.encode(null);
    fail("Expecting NullPointerException");
  } catch (NullPointerException expected) {
    assertEquals("The text to encode should not be null", expected.getMessage());
  }
}

The good thing about this pattern is that we can verify exactly where the exception we are expecting should be thrown. The downside is that is verbose and error-prone. It is easy to forget to call fail (line 6,) resulting in a test that never fails, even if the expected exception is never thrown!

JUnit 4 introduced the attribute expected in its @Test annotation, where we can specify the type of exception should be thrown by the code to test:

@Test(expected = NullPointerException.class)
public void shouldThrowNpeIfArgumentIsNull() {
  encoder.selectEncoding("Ewokeese");
  encoder.encode(null);
}

IMHO, it made things worse. It definitely results in cleaner code, but the price to pay is that now we can’t check if the message of the expected exception is correct and we can’t specify the line of code that is supposed to throw an exception. If an NPE is thrown, which line actually did it?

Enter ExpectedException rule

JUnit 4.7 introduced rules, which are another extension mechanism for JUnit (you can read more about rules here.) Among those rules, my favorite is ExpectedException, because it allows us, with only a couple of lines of code, to verify both the type and the message of an expected exception *and* specify where the exception should be thrown (well, more or less.)

public class EncoderTest {
 
  @Rule public ExpectedException thrown = ExpectedException.none();
 
  @Test
  public void shouldThrowNpeIfArgumentIsNull() {
    encoder.selectEncoding("Ewokeese");
    thrown.expect(NullPointerException.class);
    thrown.expectMessage("The text to encode should not be null");
    encoder.encode(null);
  }
}

The sour smell of code duplication

So far so good. Something I noticed is that in my code I was checking for the same type of exceptions over and over, resulting in code duplication. For example, I had this code in too many places:

thrown.expect(AssertionError.class);

Yeah, I know, this is only one line of code, but duplication really bothers me. I wished I could write the following:

thrown.expectAssertionError("[Test] expecting:<'Leia'> but got <'Yoda'>");

Actually, it is possible. We just have to write our own ExpectedException rule. Subclassing org.junit.rules.ExpectedException is not possible, since its constructor is private. Copy/pasting ExpectedException‘s code is a terrible idea. There is a better way.

The solution

I implemented my own ExpectedException by simply wrapping the JUnit one, protecting myself from future changes in ExpectedException‘s implementation:

public class ExpectedException implements MethodRule {
 
  private final org.junit.rules.ExpectedException delegate = org.junit.rules.ExpectedException.none();
 
  public static ExpectedException none() {
    return new ExpectedException();
  }
 
  private ExpectedException() {}
 
  public Statement apply(Statement base, FrameworkMethod method, Object target) {
    return delegate.apply(base, method, target);
  }
 
  public void expectAssertionError(String message) {
    expect(AssertionError.class);
    expectMessage(message);
  }
 
  public void expectNullPointerException(String message) {
    expect(NullPointerException.class);
    expectMessage(message);
  }
 
  public void expect(Throwable error) {
    expect(error.getClass());
    expectMessage(error.getMessage());
  }
 
  public void expect(Class<? extends Throwable> type) {
    delegate.expect(type);
  }
 
  public void expectMessage(String message) {
    delegate.expectMessage(message);
  }
}

Conclusion

The (relatively) new ExpectedException rule is a nice addition to JUnit. It brings the benefits of the previous approaches for verifying expected exceptions, without their downsides. As useful as it is, ExpectedException can also introduce code duplication if we are verifying the same type of exception many times in our test suite. As a workaround, creating our own ExpectedException that already knows about the type of exceptions we expect in our test suite can reduce code duplication and make test code a little more readable. Writing one is easy, we just need to implement the interface org.junit.rules.MethodRule and delegate the actual behavior to a org.junit.rules.ExpectedException, something that takes seconds to do in modern IDEs.

Feedback is always welcome :)

 

From http://alexruiz.developerblogs.com/?p=1530

JUnit

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • The Power of Docker Images: A Comprehensive Guide to Building From Scratch
  • Building a RESTful API With AWS Lambda and Express
  • Test Execution Tutorial: A Comprehensive Guide With Examples and Best Practices
  • Keep Your Application Secrets Secret

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: