One other to bear in mind is to avoid adding too much boiler code into the
production solely for the purpose of testing. I am typically a OO person,
but I wouldn't sacrifice code clarity and readability for it.

On Fri, Jul 15, 2016 at 12:14 PM, Kirk Lund <kl...@pivotal.io> wrote:

> We recently introduced GeodeSecurityUtil for GEODE-17, and I'm looking into
> ways to refactor this class or the classes using it to better facilitate
> unit testing of those classes. I'm hoping that others on this list will
> chime in with ideas and opinions. GeodeSecurityUtil itself is a collection
> of public static methods that use Apache Shiro and callback APIs (such as
> SecurityManager) in Geode.
>
> First, a few general pre-assertions:
> A.1) we want to embrace clean coding and solid OOP coding practices,
> A.2) we want to write fast running unit tests that fully isolate the class
> under test (this typically uses mocking),
> A.3) we want to be able to unit test any code in a class even if it's in a
> method that invokes public static methods in another class,
> A.4) simple mocking with Mockito is much preferred over using Powermock,
> A.5) we want to also write integration tests but the emphasis is on fast
> unit tests.
>
> There are quite a lot of procedurally static classes already in the Geode
> codebase, so I'm hoping some of these ideas will be applicable to helping
> out others working on other areas of the code as well.
>
> Any class that has calls to a collaborator with public static methods makes
> the unit testing of that class much more difficult:
>
> B.1) you cannot spy the static util class to verify that the class under
> test invoked it with proper parameters
>
> B.2) you cannot mock the static util class to return expected values to the
> class under test
>
> If the following is a util type class:
>
> public class GeodeUtils {
>
>   public static void persist(String key) {
>     ...
>   }
>
>   public static String getValue() {
>     ...
>  }
> }
>
> ...then there are two potential ways to facilitate unit testing of classes
> that depend on GeodeUtils:
>
> C.1) change all methods in GeodeUtils to be non-static and pass in an
> instance of GeodeUtils to the class constructor of any class that will use
> it
>
> C.2) wrap these statics with an interface and default implementation that
> delegates to the static calls:
>
> public interface GeodeService {
>
>   void persist(String key);
>
>   String getValue();
> }
>
> public class DefaultGeodeService implements GeodeService {
>
>   public void persist(String key) {
>     GeodeUtils.persist(key);
>   }
>
>   public String getValue() {
>     return GeodeUtils.getValue();
>   }
> }
>
> public class DurableOperation {
>
>   private final Properties config;
>   private final GeodeService geodeService;
>
>   public DurableOperation(Properties config) {
>     this(config , new DefaultGeodeService());
>   }
>
>   DurableOperation(Properties config, GeodeService geodeService) {
>     this.config = config;
>     this.geodeService = geodeService;
>   }
>
>   public void perform(String key) throws IOException {
>     ...
>     this.geodeService.persist(key);
>     ...
>   }
> }
>
> public class DurableOperationTest {
>
>   @Test
>   public void shouldPersistKey() throws Exception {
>     // given
>     Properties config = generateFancyOperationConfig();
>     GeodeService spyGeodeService = spy(GeodeService.class);
>     when(spyGeodeService.getValue()).thenReturn("bar");
>     DurableOperation durableOperation = new DurableOperation(config,
> spyGeodeService);
>
>     // when
>     durableOperation.perform("foo");
>
>     // then
>     verify(spyGeodeService, times(1)).persist("foo");
>   }
> }
>
> C.3) do C.2 until C.1 can occur (what prevents us from just doing C.1?)
>
> I believe that in general we want to use the solution in C.1 where
> possible.
>
> To foster some discussion:
>
> D.1) do we agree on the pre-assertions I listed in A.1-5?
> D.2) do we have procedurally static classes that cannot or should not be
> changed from static to non-static as described by C.1?
> D.3) are there any other approaches that will better facilitate unit
> testing of classes that depend on static collaborators?
>
> I'd like to ultimately encourage the Geode dev community to avoid creating
> new classes that consist of static methods and state. I believe we can do
> this and that it's for the best.
>
> -Kirk
>



-- 
Cheers

Jinmei

Reply via email to