Writing unit tests for abstract classes

24May08

If you have created an Abstract Class you may want to test its non abstract methods. But there is one problem: we can’t instantiate abstract classes.

There are two ways to test their non abstract methods:

Testing Abstract Classes Through Their Children’s

Suppose we have the following abstract class named Person:

public abstract class Person {
    private String firstName;
    private String lastName;

    public abstract void doAnything();
    public String getFullName(){
        return firstName + " " + lastName;
    }
    // Getters and setters here...
}

And a Boss class that extends Person:

public class Boss extends Person{
    @Override
    public void doAnything() {
        System.out.println("Do anything...");
    }
}

And you want to test the Person.getFullName() method. So you must create the test below:

public class PersonTest {
    Person person;
    @Before
    public void setUp() {
        person = new Boss();
        person.setFirstName("Anderson");
        person.setLastName("Dias");
    }
    @Test
    public void getFullName(){
        assertEquals("Anderson Dias", person.getFullName());
    }
}

On this first case, it will work fine and the test will pass no matter. But there is a problem, because it’s been assumed that the Boss class will never override the getFullName() method. If the Boss class changes, the test will fail.

public class Boss extends Person {
    @Override
    public String getFullName(){
        return "Mr. " + super.getFullName();
    }
    @Override
    public void doAnything() {
        System.out.println("Do anything...");
    }
}

So, what to do? Let’s see another way to test Abstract Classes.

Creating Mock Implementations for Abstract Classes

There is a simple way to test them. You can create a mock class that simulates the implementation of an abstract class. You will guarantee that the non abstract methods will be the same of the parent abstract class.

Let’s see a sample Mock implementation:

public class MockPerson extends Person {
    @Override
    public void doAnything() { }
}

Notice that you don’t have to test the Person abstract class methods right now. So you don’t have to implement the doAnything() method body on the Mock implementation.

And our Test Case will be:

public class PersonTest {
    Person person;
    @Before
    public void setUp() {
        person = new MockPerson();
        person.setFirstName("Anderson");
        person.setLastName("Dias");
    }
    @Test
    public void getFullName(){
        assertEquals("Anderson Dias", person.getFullName());
    }
}

That’s a simple way to test abstract methods.

Of course there are some specifics cases that Mock Objects don’t solve, in those cases you will need to test using the first strategy.

public abstract class Person {
    private String firstName;
    private String lastName;

    public abstract void doAnything();
    public String getFullName(){
        this.doAnything();
        return firstName + " " + lastName;
    }
    // Getters and setters here...
}

In this case our non abstract method ( Person.getFullName() ) calls the abstract method ( Person.doAnything() ), and the implementation of Person.doAnything() method may be decisive for the Person.getFullName() return. So, the only way to test it will be by the Person children classes.

I hope you enjoy it.

Thanks to Raquel Carsi for help me to write this post.

Advertisements


2 Responses to “Writing unit tests for abstract classes”

  1. Hi! I was surfing and found your blog post… nice! I love your blog. 🙂 Cheers! Sandra. R.

  2. 2 coffy

    Hi, to avoid misunderstanding you should update your blog and exchange “Mock” term with “Stub” term. There is a nice explanation about differences here: blog http://martinfowler.com/articles/mocksArentStubs.html.

    Best Regards


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: