Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock Dispatch http client in Scala test?

I've got some code dealing with HTTP requests and I want to unit-test it.
Thus I'm trying to mock dispatch.Http or even better dispatch.HttpExecutor (0.8.5) with Scala (2.9.1.final), Mockito (1.9.0-rc1) and ScalaTest (1.6.1) but even can't make my test code compilable.
Here in MyHttpTest I want to receive certain HTTP response for any HTTP request:

import org.scalatest.FunSuite
import org.scalatest.mock.MockitoSugar
import org.mockito.Mockito.when
import org.mockito.Matchers.any
import dispatch._

class MyHttpTest extends FunSuite with MockitoSugar {
  test("example") {
    val httpMock = mock[HttpExecutor]
    when(httpMock.apply(any(classOf[Handler[String]]))).thenReturn("Some_HTTP_response")
  }
}

But it produces compilation error:

error: overloaded method value thenReturn with alternatives:
(httpMock.HttpPackage[String],<repeated...>[httpMock.HttpPackage[String]])org.mockito.stubbing.OngoingStubbing[httpMock.HttpPackage[String]] <and>
(httpMock.HttpPackage[String])org.mockito.stubbing.OngoingStubbing[httpMock.HttpPackage[String]]
cannot be applied to (java.lang.String)
when(httpMock.apply(any(classOf[Handler[String]]))).thenReturn("Some_response")

So how to mock dispatch client?

like image 655
aka_sh Avatar asked Dec 26 '11 06:12

aka_sh


2 Answers

I was going to answer this with a suggestion that you should try ScalaMock instead of Mockito, because I wrongly assumed that the problem you were having was caused by Mockito not really understanding Scala (whereas ScalaMock has been created in Scala from the ground up). However:

  1. That's not your problem, and
  2. It turns out that ScalaMock fails when trying to mock HttpExecutor because it doesn't know how to handle a type defined in a package object (ExceptionListener). Damn! I'll fix it ASAP - thanks for bringing it to my attention.

Anyway, you can't create an instance of HttpExecutor#HttpPackage because it's an abstract type. So to get around it, you need to extend HttpExecutor and make HttpPackage concrete. For example:

class MyHttpTest extends FunSuite with MockitoSugar {
  trait TestHttpExecutor extends HttpExecutor {
    type HttpPackage[T] = T
  }
  test("example") {
    val httpMock = mock[TestHttpExecutor]
    when(httpMock.apply(any(classOf[Handler[String]]))).thenReturn("Some_HTTP_response")
  }
}
like image 133
Paul Butcher Avatar answered Nov 15 '22 08:11

Paul Butcher


I don't know anything about Scala. But as a general rule, you shouldn't be trying to mock a class that isn't your own; and it seems to me that HttpExecutor above is one such class.

A pattern that works really well for testability is to develop a class that acts as a wrapper around such classes, but has no functionality of its own. Then write (at least) two separate test classes -

  • an integration test class for your wrapper class, to make sure that you're calling HttpExecutor correctly;
  • unit test classes for whichever classes use your wrapper class.

The integration test class shouldn't have any mocking at all. The unit tests will have a mock for your wrapper class.

If I've misunderstood your question - and HttpExecutor really is your own class - then post again and I'll try to provide a different answer.

like image 31
Dawood ibn Kareem Avatar answered Nov 15 '22 06:11

Dawood ibn Kareem