January 23, 2010

Stubrn - Some Ideas about Concise Stubs in Java

Motivation

There are a lot of cool Java Mock frameworks out there in the wild. I am a great fan of JMock myself, but nevertheless, they are Mock frameworks. As a matter of fact, sometimes i just want to use a Stub and not a Mock. That said, and not finding a proper solution to fit my needs, i started considering my demands. If you are as eager as me to see the results of this quest, feel free to read on!

Of course, creating a Stub should be straight forward. Not much boilerplate, not much code duplication. Usually they should simply let the stubbed class return something that is appropriate in the current test. How do we do stubbing currently? If we assume we talk about stubbing interfaces, a quite painless approach would be implementing an anonymous class of our Interface-to-be-stubbed directly in the test. Hm, this is good, as long as the interface is quite thin. If we have one which consists of several methods, and our System Under Test just makes use of a fraction of these methods, it is more than cumbersome to implement all of them. Hence, a Stub framework should enable us to just provide what's required.

How to Stub

Well, things are explained best by showing examples. So here comes ours: Let's assume we have some ... er... Entity :)

public class Entity {

    private int id;
    private String name;
    private int age;

    // ...
}

Of course a DAO to persist the Entity:

public interface EntityDAO {

    public List<Entity> findByName(String name);
    public Entity findById(int id);
    public void store(Entity entity);
    public List<Entity> findByAge(int age);
    public List<Entity> findByAge(int from,int to);
}

and some client of the DAO, our controller:

public class Controller {

    private EntityDAO entityDAO;

    public void setEntityDAO(EntityDAO entityDAO) {
        this.entityDAO = entityDAO;
    }

    public List<Entity> listEntities(String name){
        return entityDAO.findByName(name);
    }
}

Yeah, you already know where this leads to, but let me put it explicitly. Assume the SUD is the controller. Hence when we write a unit test for the controller, we want to get rid of the whole persistence layer. We don't want to use our real EntityDAOImpl, which most likely uses JDBC or some ORM to access a real database. No sir. We just want to test listEntities(), and it is enough for us, that the DAO simply returns some entities here. It is irrelevant, where they originate from. If we would stub the interface with an anonymous class, we would have to implement all the methods. How annoying is that? We know, the controller uses just that single one. Being a lazy person, i also just want to implement that one! So what do you think about this:

Stubbery stubbery = new Stubbery();

EntityDAO stub = stubbery.stubFor(EntityDAO.class,new Object(){
    List<Entity> findByName(String name) {
        return Lists.newArrayList(new Entity("foo"),new Entity("foo"));
    }
});


Controller sud = new Controller();
sud.setEntityDAO(stub);

Assert.assertEquals(sud.listEntities("foo").size(),2);

In the spirit of JMock's Mockery we have our Stubbery. It is a factory to create Stubs of the given interface as done by stubFor. You tell the Stubbery which interface should be stubbed and provide a holder, an object which provides a method with the same signature you want to implement on the interface. The Stubbery takes care, that there is something which looks like your interface, and which calls the respective method on the holder. And now we need to make some steps back. This is surely not the way polymorphism is done in Java. I am well aware of this, and of course we will discuss the disadvantages later. But on the other hand, we must be fair. We already know there are different forms of polymorphism and only some of them require explicitly typed interfaces. So after all, we sacrifice static compiler checks for code conciseness and need to judge, if this is a fair trade.
If we have accepted this argumentation, we could go a step further. We want to be even more concise, hence let us do something like:

Stubbery stubbery = new Stubbery();

EntityDAO stub = stubbery.stubFor(EntityDAO.class,new Object(){
    @ByName List<Entity> findByName = Lists.newArrayList(new Entity("foo"));
});

Controller sud = new Controller();
sud.setEntityDAO(stub);

Assert.assertEquals(sud.listEntities("foo").size(),1);

So what do we do here? Again, the Stubbery creates a Stub by using a holder. But this time, the holder has no respective method, but only a field, matching the return type and the name of our desired method. Yes, this is coming close to dark magic. Hence we've added the Annotation, which marks the field explicitly to be used as the result of method-to-be-stubbed.

Limitations and Disadvantages

After explaining the core idea, we need to come to the dark side of this nice concept. Under the hood we use a java.lang.reflect.Proxy. And the drawback here is, we can just create Proxies on Interfaces. This means, we can just stub Interfaces. But again, this is the same limitation Mock frameworks have to obey to, so we have to live with it. My main concern has already been mentioned. The way the holder is associated with stubbed interface is not related at all to any way Java allows polymorphism, and the most sad consequence of this fact is, that it will not be affected by refactoring. If you change the signature of the interface, nobody knows that your test contains some holder object, which makes strong assumptions about the details of that signature. Once changed, it does not match anymore, hence your stub will not work. But there's always a But. Our But says: It's the same for dynamically typed languages. Those fail not at compile time, but only at test time. And since we talk about Stubs, which live in test world, it might be acceptable to fail just during test time!

Final Words

So much of the basic idea. I've implemented a prototype and called it Stubrn. It could be found at Github and is currently in an early version, but those concepts introduced here work basically. So if you have any further concerns or improvements, don't hesitate and let me know. You might also like to browse all articles on Stubrn.

5 comments:

Jens Schauder said...

Nice.

But the link to your polymorphism article morphed, i.e. it's broken.

Lars Girndt said...

Thanks, Jens. Link fixed, the leading / was missing, narf :)

rliesenfeld said...

You can do something similar with a JMockit mock-up class:

EntityDAO stub = new MockUp() {
@Mock List findByName() {
return Lists.newArrayList(new Entity("foo"));
}
}).getMockInstance();

Controller sud = new Controller(); sud.setEntityDAO(stub); assertEquals(1, sud.listEntities("foo").size());

There is no limitation, though, as EntityDAO could also be a final class.

rliesenfeld said...

Oops, it should be "MockUp<EntityDAO>()" instead of "MockUp()".

Lars Girndt said...

@Rogerio Aha! Thanks for pointing that out. Yes, i took a look at it, indeed it seems to be a complete implementation of this idea (damn, so i wasn't the first :) ).

Their tutorial gives a good overview how they do it.