Mocking ResourceBundle

If you want to unit test a method that depends java.util.ResourceBundle, and want to isolate bundle access code with mocking ResourceBundle, using for example, JMock Dynamic Mocking Library, you will face with a restriction, that commonly used methods, such as getString(key) are defined as final in ResourceBundle class. There is no way to extend and override final method declarations.

Luckily, there is an abstract subclass called ListResourceBundle, which can be used during unit test setups to mock ResourceBundle usage. The following is an excerpt from a unit test, that a JSF backing bean which fetches application messages from a ResourceBundle during runtime;

 

public class ApprovalPageCode {
    private ResourceBundle resourceBundle;
    public ResourceBundle getResourceBundle() {
        if(resourceBundle == null) {
            resourceBundle = ResourceBundle.getBundle("msgResources");
        }
        return resourceBundle;
    }
    public void setResourceBundle(ResourceBundle resourceBundle) {
        this.resourceBundle = resourceBundle;
    }
    public String doSuccessOperation() {
        String outcome = getResourceBundle().getString("msgSuccess");
        return outcome;
    }
}

public class TestApprovalPageCode extends TestCase {
    class MsgResourceBundle extends ListResourceBundle {
        private Object[][] contents = new Object[][]{
            {"msgSuccess","success message"},
            {"msgError","error message"}
        };
        protected Object[][] getContents() {
            return contents;
        }
   };
   public void testSuccess() {
       ApprovalPageCode pageCode = new ApprovalPageCode();
       pageCode.setResourceBundle(new MsgResourceBundle());
       String outcome = pageCode.doSuccessOperation();
       assertEquals(outcome,"success message");
   }
}

As you can see above, ApprovalPageCode needs a ResourceBundle, and creates one using property file if there is no resource bundle provided with it using its setter method. During unit test we created an inner class named MsgResourceBundle, which extends from ListResourceBundle to provide required messages, and set an instance of it into ApprovalPageCode instance before running test method. As a result, our test gets isolated from accessing file system to create resource bundle during our unit tests.