5

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?

Urist McDev
  • 498
  • 3
  • 14
aka_sh
  • 549
  • 1
  • 7
  • 18
  • Just in case it would be useful for someone - here is the code which finally uses the cooked (by Paul Butcher) mock: `println(httpMock(url("http://google.com") as_str))` – aka_sh Dec 26 '11 at 20:26

2 Answers2

6

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")
  }
}
Paul Butcher
  • 10,722
  • 3
  • 40
  • 44
  • thank you much, your code works (better to say - compiles) like it should! I was somewhere close to your answer but I couldn't realize how to take out the real type (String) from that HtppPackage. – aka_sh Dec 26 '11 at 20:20
  • P.S.: @davidw was damn right when suggested me to extend foreign class before mocking it! – aka_sh Dec 26 '11 at 20:28
1

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.

Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110
  • 1
    Firstly, you are right, HttpExecutor - is a foreign trait(comes from dispatch lib). Secondly, I definitely agree that integration test is needed - and I've got couple of. My desire is to have also a pure "unit" test. But as for me- mocking of foreign interfaces/classes is absolutely normal - you just mock some behavior no matter if it's your or not. Even more, in very this case HttpExecutor extending won't help me - cause I don't understand how to *describe* the behavior itself (I try but got compilation errors =)). – aka_sh Dec 26 '11 at 09:14
  • 1
    OK, if you insist on mocking types that aren't yours. You can google for yourself and find plenty of literature that explains why this is a bad idea. In your specific case, though, I think what might be happening here is that the apply() method of HttpExecutor returns something that isn't String, but you're trying to make the mock of it return a String. Mockito won't let you do this; the value returned by the mock has to have the same type as the value returned by a real object of that class. – Dawood ibn Kareem Dec 26 '11 at 09:34
  • 1
    1. Let's omit discourse about mocking theory - cause it's not the cause of my problem. 2. Again I agree with you, the code isn't compilable cause *apply()* method should return some internal type *HttpPackage[String]* but I can't figure out how to make the *when-thenReturn* code do it. – aka_sh Dec 26 '11 at 10:58
  • So, you need to make some kind of object of type HttpPackage[String]; then pass it as the argument to thenReturn(). Since I'm not familiar with Scala or the dispatch library, I can't suggest how to construct this object, but that's not really a question about mocking. – Dawood ibn Kareem Dec 26 '11 at 19:56