Entries in development (7)

Wednesday
Oct302013

Asserting Exceptions With JUnit Rules: IsEqual Matcher

In my first post on asserting exceptions with JUnit’s Rules feature, I showed how to test that a specific type of exception is thrown with expected substrings in the error message. In my second post, I showed how we can write a custom Matcher to inspect the contents of the exception. In this post, I’ll show you how to take advantage of the stock IsEqual matcher to accomplish the same task, but with less work.

IsEqual Matcher

This Matcher is straightforward - it evaluates whether two objects are equal by calling equals(Object) on one of the objects that isn’t null, passing in the other. So, to use it with our custom exception, we’ll need to make sure that our equals(Object) method correctly evaluates two of its instances.

The default behavior of equals(Object obj) is to check if two objects are the same instance:

The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).

This won’t help us here, because we’ll be comparing exceptions thrown in our code with one we instantiated in our unit test. We’re going to have to implement equals(Object) ourselves.

Implementing equals(Object)

Here’s my simple custom exception:

You have to be careful when implementing either either equals(Object) or hashCode(). The rule is that if you implement either of these methods, then you need to implement both. Two objects that are equal must have the same hash code. If they don’t, and you try to add two distinct, but equal instances of a class to a Map, they’d both be accepted. This is because internally, the Map stores the items in “buckets” based on their hash codes, and then only has to check equality within a bucket. If two objects have different hash codes, then they won’t be compared to each other.

Your IDE should have the ability to generate what we need here. If you’re using Eclipse (I recommend the STS version), right-click in the source file, select “Source”, and the select “Generate hashCode() and equals()…”

After selecting that option, choose which private members will be used in the two methods. I recommend selecting “Use blocks in ‘if’ statements” in order to help wrong code look wrong, should someone modify these methods down the road.

Here’s our final ErrorCodeException class with the newly generated code:

Verifying equals(Object) and hashCode()

Even though we generated this code, we still need to test it. Here’s the test fixture for ErrorCodeException:

Using the IsEqual Matcher In Our Unit Tests

Now that we’ve implemented equals(Object) and hashCode() for our custom exception, we can use the IsEqual Matcher to setup an expectation for a specific exception.

In the first test, I create an IsEqual Matcher with the exception that I want to compare the thrown exception to. No custom Matcher was required, and my custom exception is now more useful because of it.

In my second test, I include the “old way” of checking exceptions to demonstrate how much easier and more readable exception tests are when using JUnit’s Rules feature.

Tuesday
Oct292013

Asserting Exceptions With Junit Rules: Custom Matchers

In my previous post, I demonstrated how to use JUnit’s Rules feature to assert expected assertions in your unit tests. In this post, I’ll show you how to write custom Matchers that will help give you more power when inspecting your exceptions.

Maven Dependencies

This demo uses the following Maven dependencies:

Custom Exception

We’ll start with a custom exception which does little more than remember the error code at the time the exception was thrown.

Our Exception Matcher

When we pass our Matcher to JUnit’s ExpectedException instance, we’re given a chance to match the exception itself, not the message. In this case, we’re going to write a Matcher that makes sure that the exception’s error code was as expected. We can only match on an instance of our _ ErrorCodeException_, so we’ll save some effort and extend TypeSafeMatcher.

From the documentation:

TypeSafeMatcher : Convenient base class for Matchers that require a non-null value of a specific type. This simply implements the null check, checks the type and then casts.

Example Tests With ExpectedException and Our Custom Matcher

With the components in place, let’s start testing. Of course, if you only have one or two error test cases, then a custom Matcher might take more work than it saves, but you end up with code that any developer should be able to read, which might reduce maintenance costs.

Asserting Exceptions The Old Way

To demonstrate the benefits of using custom Matchers with JUnit’s ExcpectedException, here are the alternatives that you’re probably familiar with, with inline comments explaining why they’re not ideal.

Monday
Oct282013

Asserting Exception Messages With JUnit Rules

If you’re not familiar with JUnit’s @Rule feature for asserting exceptions in your tests, then read on - you’re about to start using it.

Assert Exception Type

It’s very simple to assert that a given type of exception is thrown in a JUnit test case with the following:

Assert Exception Message (The Old Way)

But, what if you want to be more specific, and check the message itself? I’ve always done the following:

Heres’s another variant you’re probably familiar with:

Assert Exception Message With JUnit Rules

The above methods always felt like hacks. I recently came across JUnit’s @Rule feature, which saves tons of code and is much easier to read. You first define your public ExpectedException instance, and give it a @Rule annotation. Then, in each test case that wants to use it, you set what type of exception you’re expecting, and optionally a substring to look for in the exception message:

Since expectMessage is looking for substrings, you can use several of them to test more complicated exception messages:

More Advanced: Custom Matchers

In my next post, I’ll describe how to implement a custom Matcher for more complicated Exception assertions.

Sunday
Oct272013

Developing Software In a Changing Industry

Petri Kainulainen writes about developers complaining about the limited lifespan of programming languages:

The authors of the posts which linked to that blog post claimed that it is impossible to have a long term career in computer programming because the lifespan of programming languages is too short. I have written about this before and it shouldn’t be surprise to you that I disagree with these people.

I find it a bit absurd that someone expects that he can use programming language X for his entire career. Our industry still very young when compared to other more traditional engineering professions (I don’t claim that software engineer is really engineering). That is why I think that it is only natural that the programming languages and other tools are evolving quite rapidly.

I agree with Petri. Upon reflecting on the future of my own career, I realize that I used to worry that I'd be less effective as a software developer as I got older. So far, this has turned out to be the opposite.

At the start of my career, I had the attitude that I'd rather rewrite something on my own than to learn how to reuse someone else's work. Now, I realize how much risk that carries, and how much that slows a project down. It's true that it takes a bit of up-front effort to figure out how an open source component or framework works, but it will be rewarded many times over if I've done my homework in selecting the right component first. Mature open source libraries have already been through several rounds of bug-fixes, refactoring, and public scrutiny. My implementation would almost certainly contain simple coding errors and deep conceptual flaws until I better understand the problem space.

I no longer feel the need to prove to myself that I can solve a specific technical problem. Instead, I want to advance my project as quickly and responsibly as I can. Plenty of talented people have flooded the public domain with their hard work, and I want to leverage it.

Languages are the easy part, and every popular language will have its share of open source support. Frameworks are effort multipliers, and knowing how frameworks work and how they should work is real power. That translates across different platforms, and makes you valuable even when the job market switches to a new language – but that never happens overnight, anyway.

If you’re stuck in an old language, refusing to change, and complaining about it, then your heart probably isn’t in it anyway.

Friday
Aug302013

Builder Pattern Instead of Error-Prone Constructors

When designing your classes, rather than following the path of the unreadable telescoping constructor, or leaving yourself open for bugs where the caller incorrectly passes a value into the wrong parameter because you have several of the same type, consider the following Builder pattern.

public class Person
{
    // required
    private String firstName;

    // required
    private String lastName;

    // optional
    private String url;

    // private constructor to defer responsibility to Builder.
    private Person()
    {
    }

    public String getFirstName()
    {
        return this.firstName;
    }

    public void setFirstName(final String firstName)
    {
        if(StringUtils.isBlank(firstName))
        {
            throw new IllegalArgumentException("Person.firstName must not be blank");
        }
        this.firstName = firstName;
    }

    public String getLastName()
    {
        return this.lastName;
    }

    public void setLastName(final String lastName)
    {
        if(StringUtils.isBlank(lastName))
        {
            throw new IllegalArgumentException("Person.lastName must not be blank");
        }
        this.lastName = lastName;
    }

    public String getUrl()
    {
        return this.url;
    }

    public void setUrl(final String url)
    {
        this.url = url;
    }

    // builder class to ensure that all required fields are set while avoiding clunky, "telescopic" constructors
    public static class Builder
    {
        private Person built;

        public Builder()
        {
            built = new Person();
        }

        public Builder setFirstName(final String firstName)
        {
            built.setFirstName(firstName);
            return this;
        }

        public Builder setLastName(final String lastName)
        {
            built.setLastName(lastName);
            return this;
        }

        public Person build()
        {
            if(built.firstName == null)
            {
                throw new IllegalStateException("Person.firstName is required");
            }
            if(built.lastName == null)
            {
                throw new IllegalStateException("Person.lastName is required");
            }
            return built;
        }
    }
}

Having a private constructor will prevent anyone but the Person's Builder from instantiating a Person. The setters in the Builder return the Builder, which allows method chaining, providing a DSL-like self-documenting interface. The Builder's build() method is responsible for making sure that all properties are set before returning the Person.

Of course, this is a simple example with only two fields, so the alternative isn't exactly error prone:

Person blogger = new Person("Blake", "Caldwell");
blogger.setUrl("http://blakecaldwell.org");

But, once you add a few more required fields, the following makes your code easier to follow, while still ensuring all required fields are set.

Person blogger = new Person.Builder()
        .setFirstName("Blake")
        .setLastName("Caldwell")
        .build();
blogger.setUrl("http://blakecaldwell.org");

I first came across this pattern via a post by Petri Kainulainen. Check out his blog for great posts about Spring Data JPA and other topics.