2

Hi I want to test the generateKey method and the messages being dispatched by the Dispatcher. I have tried to mock the class and the public method verifyOtherDetails(). Inside it I created an expectation that the dispatcher method had a literal value but it always passes. Any help would be appreciated.

See bottom for my attempted code thanks.

abstract class KeyGen {

  private static void generateKey(String key, String username){
    if(Strings.isNullOrEmpty(key)){
      Dispatcher.dispatch(new WarningString(String.format("The key is null or empty for user %s", username)));
    }else{
      Dispatcher.dispatch(new InfoString(String.format("The key is correct for user %s", username)));
    }
  }

  public void verifyOtherDetails(String address, Map<String, String> favouriteFilms){
    String key ="";
    String username ="";
    generateKey(key, username);
  }
}

public class TestKeyGen {

  @Test
  public void testKey() {
    new MockUp<KeyGen>() {
      @Mock()
      public void verifyOtherDetails() {

        String key = "sfjhlkjhfkjdhlsk";
        final String username = "Daniel";
        new Expectations() {
          {
            Dispatcher.dispatch(new WarningString(String.format("The key is null or empty for user %s", username)));
          }
        };
      }
    };
  }
}
Daniel Devlin
  • 95
  • 1
  • 11
  • 2
    There is plenty of material out there already on testing private methods -- including [other answers on SO](http://stackoverflow.com/questions/34571), including the top hit if you google [the text of this question's subject line](https://www.google.com/webhp?ion=1#q=Testing%20a%20private%20Static%20method). Do those answer your question? – yshavit Oct 31 '14 at 15:52
  • I have seen the use of reflection but I wanted to see if there was a cleaner way to verify the method. I'm new to JMockit and haven't had much experience with mocking objects. – Daniel Devlin Oct 31 '14 at 16:00

2 Answers2

2

Given your design I'd say its difficult to test your method. Basically this is because you are using static methods of the dispatcher class so you can't easily mock it.

you have a coupe of options though. you could subscribe to the dispatchers messages in your tests and check that the expected messages arrive. This is the least invasive, and serves as an integration test.

The other option is to wrap your dispatcher static calls in an interface and inject a mock of this interface into your KeyGen class then test through your public method that the methods on the interface are called.

public interface DispatchWrapper{
    void dispatch(IString stringToDispatch);
}

public class StaticDispatcher : DispatchWrapper{
    void dispatch(IString stringToDispatch)
    {
            Dispatcher.dispatch(stringToDispatch);
    }
}

abstract class KeyGen {
  private DispatchWrapper wrapper;

  public KeyGen(DispatchWrapper wrapper){
      this.wrapper = wrapper;
  }
  private static void generateKey(String key, String username){
    if(Strings.isNullOrEmpty(key)){
      wrapper.dispatch(new WarningString(String.format("The key is null or empty for user %s", username)));
    }else{
      wrapper.dispatch(new InfoString(String.format("The key is correct for user %s", username)));
    }
  }

  public void verifyOtherDetails(String address, Map<String, String> favouriteFilms){
    String key ="";
    String username ="";
    generateKey(key, username);
  }
}

A third option is to move the private method to a different static class and make it public, then you can test that class (with the same issues with your static dispatcher). Then you KeyGen class can become a VerifyingKeyGen which just verifies then delegates to the other method for actually generating the key. this nicely separates the 2 concerns that you have, ie generating the new key and verifying the deatils

public static class KeyGen {

  public static void generateKey(String key, String username){
    if(Strings.isNullOrEmpty(key)){
      Dispatcher.dispatch(new WarningString(String.format("The key is null or empty for user %s", username)));
    }else{
      Dispatcher.dispatch(new InfoString(String.format("The key is correct for user %s", username)));
    }
  }

abstract class VerifyingKeyGen{

  public void verifyOtherDetails(String address, Map<String, String> favouriteFilms){
    String key ="";
    String username ="";
    KeyGen.generateKey(key, username);
  }
}
Sam Holder
  • 32,535
  • 13
  • 101
  • 181
  • Could you point me in the direction of an example. I understand what your saying but with my knowledge to date it will take a bit more reading before being able to attempt that. – Daniel Devlin Oct 31 '14 at 16:07
  • I can't help with the first bit (subscribing to the dispatcher messages), as I don't know how you subscribe to recieve messages in your application/framework. I assume you do though :). But I'll provide a wrapper example, give me a sec. – Sam Holder Oct 31 '14 at 16:09
  • An advantage of the third option is that if JMockit allows mocking of public static methods then you can test `VerifyingKeyGen` by mocking out the call to `KeyGen.generateKey` – Sam Holder Oct 31 '14 at 16:34
2

Fixed version of the test in the question:

@Tested KeyGen keyGen;
@Mocked Dispatcher dispatcher;

@Test
public void testKey() {
    keyGen.verifyOtherDetails("???", null);

    final WarningString warning = 
        new WarningString("The key is null or empty for user ");

    new Verifications() {{ Dispatcher.dispatch(warning); }};
}

(Provided WarningString implements the equals method.)

Rogério
  • 16,171
  • 2
  • 50
  • 63