0

I want to write test for GetEventPlannersRequest class.

This class looks:

    class GetEventPlannersRequest(requestIn: GetEventPlannersRequest.Request,
                              okListener: RabbitResponse.RabbitResponseListener<GetEventPlannersResponse>,
                              errorListener: RabbitResponse.RabbitErrorListener
) : AbstractWfmRabbitRequest<GetEventPlannersRequest.Request, GetEventPlannersResponse>(requestIn, GetEventPlannersResponse::class.java, okListener, errorListener) {

    override fun getExchange(): String {
        return RabbitModuleConfig.EXCHANGE_MOBILE_OUT
    }

    override fun getRoutingKey(): String {
        return WfmRabbitModuleConfig.ROUTING_KEY_WFM_EVENT_PLANNERS
    }

    override fun getType(): String {
        return WfmRabbitModuleConfig.TYPE_WFM_EVENT_PLANNERS
    }

So in tests I did something like this:

@Mock
lateinit var requestIn: GetEventPlannersRequest.Request

@Mock
lateinit var okListener: RabbitResponse.RabbitResponseListener<GetEventPlannersResponse>

@Mock
lateinit var errorListener: RabbitResponse.RabbitErrorListener

@Before
fun before() {
    MockitoAnnotations.initMocks(this)
}

@Test
fun getExchange() {
    val getEventPlannersRequest = GetEventPlannersRequest(requestIn, okListener, errorListener)

    assertEquals(getEventPlannersRequest.exchange, "mobile.outgoing")
}

And where is the problem?

Problem is that the parent class GetEventPlannersRequest

  public AbstractRabbitRequest(K body, Class<T> clazz, RabbitResponse.RabbitResponseListener<T> listener, RabbitResponse.RabbitErrorListener error) {
    super(FS.get().getSession().getTerminalId(), body, clazz, listener, error);
}

Which throwing java.lang.NullPointerException.

Is it possible to mock it somehow ? Or I need to refactor it somehow ?

UPDATE:
For now I added additional constructor:

 public AbstractRabbitRequest(String terminalId, K body, Class<T> clazz, RabbitResponse.RabbitResponseListener<T> listener, RabbitResponse.RabbitErrorListener error) {
    super(terminalId, body, clazz, listener, error);
}

So I can mock also terminalId and test it but if it is possible to mock it I also would like to know how: )

Esperanz0
  • 1,524
  • 13
  • 35
  • I think you should refactor this. To instantiate the request class you need to pass the terminalId as a parameter. The constructor shouldn't try to access a singleton state on its own. The problem with the test will go away once you make this change. – Gennadii Saprykin Jul 13 '18 at 09:10
  • @GennadiiSaprykin My opinion is also this should be refactored but... I'm writing new module in Kotlin and don't want to change to much existing implementation in case of not to much time. What You think about additional constructor for now? – Esperanz0 Jul 13 '18 at 09:12
  • This is a good idea, yes. Just add that constructor for now, but eventually you should migrate your actual code base to that constructor and get rid of the one that uses the singleton. – Gennadii Saprykin Jul 13 '18 at 09:13
  • You could also have the constructor take as parameter what `FS.get()` would return, which can then be mocked while still maintaining some 'implementation detail' inside the constructor. – JimmyB Jul 13 '18 at 09:15
  • @JimmyB I exactly did it. Look at the bottom with "UPDATE" – Esperanz0 Jul 13 '18 at 09:16
  • @Esperanz0 No, you didn't :) Your constructor takes the `String terminalId`, forcing the caller to resolve the terminalId by himself. What I mean is like `public AbstractRabbitRequest(FS fs,...) { super(fs.getSession().getTerminalId(),...); }` – JimmyB Jul 13 '18 at 09:18
  • Possibly helpful: https://stackoverflow.com/questions/21105403/mocking-static-methods-with-mockito – JimmyB Jul 13 '18 at 09:19
  • @JimmyB Ahh in this way. Sure it's also good and similar because anyway we will mock String or Fs session. Good point. Thanks : ) – Esperanz0 Jul 13 '18 at 09:20
  • @JimmyB After short time of thinking Your solution looks better for me :) – Esperanz0 Jul 13 '18 at 09:25
  • @GennadiiSaprykin Thanks for help! – Esperanz0 Jul 13 '18 at 09:25
  • You can also keep the convenience constructor that uses `FS.get()` (for application use) and add another one to take an instance of `FS` as above (for test use); the convenience constructor just calls through to the other one passing `FS.get()` as parameter. – JimmyB Jul 13 '18 at 09:30
  • OTOH, it may be better to make explicit that your class (only) uses a terminal ID, not everything available from FS, and that, if the user does not provide a `String terminalId` (by calling the convenience constructor), the default from FS will be used. – JimmyB Jul 13 '18 at 09:41

0 Answers0