views:

65

answers:

4
+1  Q: 

Testable design

I have a java class which has a static member created using Facade (Singleton).

Class A implements InterfaceA {

 private static DataStore db = DataStoreFacade.getInstance("BDB"); //singleton instance

  public void save(final String key, final String val) {
     db.save(key,val);
  }
};

Here Class A is used as a member variable for webservice (stateless bean).

I can't test this code using EasyMock because there is no way to override the DataStore instance.

There are two options.

  1. Have a constructor taking the instance of DataStore which will set to db member variable. The problem is I don't want webservice class to know which datastore instance has been created.

  2. Provide an additional protected Set Method to override the db object. This is what I have used where I create a Easy Mock object of DataStore and override the member variable. Is it the correct design.

What are the other possibilities?

A: 

Use the Supercede Instance pattern...

http://goodcoffeegoodcode.blogspot.com/2010/01/supercede-instance-pattern.html

Chris Arnold
Thx for the link. Adding a public method on singleton to override it's object is a huge concern for me. I don't think I can use macro to optionally compile the code to enable method for executing tests.
rjoshi
A: 

You're right that is bad for testability. Use dependency injection and don't go for static variable:


public class A implements InterfaceA {

  private DataStore db;

  public A(DataStore db) {
    this.db = db;
  }

...

}

to inject or build either use dependency-injection framework (e.g. spring) or build the object somewhere in bootstrap factory code yourself.

production code:


new A(DataStoreFacade.getInstance("...");

test-code:


public void test_xxx(){
  DataStore db = EasyMock.createMock(DataStore.class);
  //... do some expectations and replay(db)
  InterfaceA a=new A(db);
  //...

}

manuel aldana
This is how we have implemented now where Facade class creates the instance of DataStore. The issues is user of the class A need to know which datastore instance to be created which I want to hide.E.g In this ImplementationA a = new A (DataStoreFacade.getInstance("bdb"));As I mentioned Class A is a member of WebService wrapper class and I don't want that class to know about which instance to be created. I want that logic to be part of Class A and not the wrapper class.
rjoshi
A: 

Well, the original code is already testable. Here is a unit test for it, using JMockit:

@Test
public void testSave(final DataStore mockDb)
{
    final String key = "aKey";
    final String value = "aValue";

    new A().save(aKey, aValue);

    new Verifications()
    {{
        mockDb.save(key, value);
    }};
}

If needed, the DataStoreFacade class could be mocked too.

Rogerio
A: 

Why not make the db member protected, and in your test project inherit it and override that member:

project 
{
    Class A
    {
        protected static db = ...
        public void Save(...) { ... }
    }
}

test_project
{
    Class B : A
    {
        protected override static db = ... (create test db)
    }

    Class testB
    {
        public A a;

        public void Setup()
        {
            this.a = new B();
        }

        public void TearDown()
        {
            // delete a
        }

        public void TestSaveKey()
        {
            // test a
        }
    }
}

It's still hidden from consumers of the code/library, the test object isn't cluttering the production code, and the behaviour will be tested as if it were the production version.

Beware though, that having a static member for your db object could cause troubles for your tests if it's not cleaned up properly after each test.*

  • I know that you probably already know this, but I'm saying it for completeness.
SnOrfus