Core Java Books

Showing posts with label testing. Show all posts
Showing posts with label testing. Show all posts

Monday, 28 March 2011

Providing Mock API's at Runtime

This article is about how I provide a mock api's to my applications at runtime so I can test them without external services being involved.

Many of the application I work on make use of api's to servers, communications engines and so on. I find it useful to be able to test my application with mock API's so I have more control of the tests on it and can test it standalone. Also the mechanism provided allows me to run my application when a service has yet to be delivered but is defined. I could make use of dependency injection if I was to drag JEE api's into my build but I prefer the simple approach. It might not be perfect but it works.

Lets say I have an external interface that my application makes use of:


public interface Service {
    void addListener(final ServiceListener listener);
    void removeListener(final ServiceListener listener);
}


Now in my application I would typically construct a concrete class either directly  or via a factory method which implements the interface contract. Whilst testing I would like to actually provide another version of the implementing class which can be used to test my application with the interface:


public class MockService implements Service {

    private static List<ServiceListener> listeners = new ArrayList<ServiceListener>();

    public void addListener(ServiceListener listener) {
        listeners.add(listener);
    }

    public void removeListener(ServiceListener listener) {
        listeners.remove(listener);
    }

    public void newRequestReceived(final ExternalRequest request) {
        RequestEvent event = new RequestEvent(request);
        for(ServiceListener listener : listeners) {
            listener.notifyRequestEvent(event);
        }
    }

}

I provide the mock class making use of a command line property:


java -Dservice.api.classname=com.webbyit.MockService -jar myapp.jar



Now in the code of my app I make use of the property (maybe within a factory method) and construct the class provided rather than the default class:


private static Service getService() {
  

    synchronized (ServiceLock) {
        if (Service == null) { 

            String serviceClassName = System.getProperty("service.api.classname");

                if (serviceClassName == null) {
                     Service = new RealService();
                else {
                    try {
                        Service = (ServiceClass.forName(serviceClassName).newInstance();
                    catch (InstantiationException e) {
                        throwCallServiceInitialisationException(serviceClassName, e);
                    catch (IllegalAccessException e) {
                        throwCallServiceInitialisationException(serviceClassName, e);
                    catch (ClassNotFoundException e) {
                        throwCallServiceInitialisationException(serviceClassName, e);
                    }
                }
            }
        }
        return Service;
    } 

}

So what I have done is test for an alternative class being specified by a property (via the command line). If set the code attempts to construct the alternative class and use that instead of the default class usually used by the application.