Search code examples
unit-testingcachingmockitogemfirespring-data-gemfire

gemfire cacheclosedexception the cache has not yet been created


I am trying to write unit test for a method which uses an instance of cache as below

public void method(String abc) {
....
....
Cache cache = CacheFactory.getAnyInstance();
....
....
}

I know mocking is the way to resolve this dependency on cache. I am new to mocking and using mockito and not sure on how to pass the mocked cache to the method.

@Mock
Cache cache;

@Test
public void testMethod(){

   doReturn(cache).when(CacheFactory.getAnyInstance());
   method("abc");

}

The above is what I've tried and got the error.


Solution

  • If you are testing some code path in your application component that calls CacheFactory.getAnyInstance() (such as method("abc")?), then you must ensure that the method gets a reference to the mock Cache another way since you cannot mock a static method on a class (i.e. getAnyInstance() on CacheFactory), at least not without some help from a framework like PowerMock. For example...

    public class ExampleApplicationComponent {
    
      public void methodUnderTest(String value) {
        ...
        Cache hopefullyAMockCacheWhenTesting = CachFactory.getAnyInstance();
        ...
        // do something with the Cache...
      }
    }
    

    Of course, this will fail. So you need to restructure your code a bit...

    public class ExampleApplicationComponent {
    
      public void methodUnderTest(String value) {
        ...
        Cache cache = fetchCache();
        ...
        // do something with the (mock) Cache...
      }
    
      Cache fetchCache() {
        return CacheFactory.getAnyInstance();
      }
    }
    

    Then in you test case in your test class...

    public class ExampleApplicationComponentTest {
    
      @Mock
      private Cache mockCache;
    
      @Test
      public void methodUsesCacheProperly() {
        ExampleApplicationComponent applicationComponent = 
            new ExampleApplicationComponent() {
          Cache fetchCache() {
            return mockCache;
          }
        };
    
        applicationComponent.method("abc");
    
        // assert appropriate interactions were performed on mockCache
      }
    }
    

    So as you can see, you can override the fetchCache() method in your anonymous ExampleApplicationComponent subclass within you test case to return the mock Cache. Also note, the fetchCache() method was deliberately made "package-private" to limit it's accessibility to primarily the test class (since test classes usually and should reside in the same package as the class under test). This prevents the fetchCache method from escaping and becoming part of your API. While other classes in the same package can access the method of an instance of the ExampleApplicationComponent class, you at least retrain control over that usage (and of course there is not substitute for good documentation).

    To see other examples of this in practice, have a look as Spring Data GemFire's CacheFactoryBeanTest class (for instance, and specifically), which does exactly what I described above using Mockito.

    Hope this helps.

    Cheers! -John