0

I'm using elastic4s as my access layer to ElasticSearch, and I'm trying to write some unit tests in my application. I'm using scalaMock as my mocking library. I want to mock the elastic4s client.execute function so I will be able to test my code.

this is the tested code:

def insert(elasticDbConnection: ElasticClient, entIndexName: String, entTypingName: String, autoId: String, newJsonEntVal: String): Option[List[String]] = {

    import com.sksamuel.elastic4s.http.ElasticDsl._
    val req: IndexRequest = indexInto(index = entIndexName, `type` = entTypingName)
        .id(id = autoId).source(newJsonEntVal).refreshImmediately

    val insertRequests: List[IndexRequest] = List(req)

    val execRes: Future[Response[BulkResponse]] = elasticDbConnection.execute(bulk(insertRequests))

    val insertRes: BulkResponse = execRes.await.result

    val insertedEnts = insertRes.successes.map(resItem => resItem.id).toList

    Some(insertedEnts)
}

now the unit test code is:

...
import com.sksamuel.elastic4s.http.ElasticDsl._

val execRes: Future[Response[BulkResponse]]= mock[Future[Response[BulkResponse]]]
val elasticClientMock = mock[ElasticClient]
(elasticClientMock.execute _).expects(_:BulkRequest).returns(execRes).once()

testElasticsDal.insert(elasticClientMock, "indexName", "entType", "test-id", "{testField:\"testValue\"}")

I'm getting an error : "Type mismatch, expected: FunctionAdapter1[BulkRequest, Boolean], actual: BulkRequest Type mismatch, expected: MockParameter[BulkRequest], actual: BulkRequest"

What am I doing wrong? how should I test my application code? and how should I mock the client?

Thank you

D. bachar
  • 21
  • 6
  • Seems `execute` expects a whole bunch more parameters than just your BulkRequest, so you probably need to deal with these also. `def execute[T, U, F[_]](t: T)(implicit functor: Functor[F], executor: Executor[F], handler: Handler[T, U], manifest: Manifest[U]): F[Response[U]]` – Philipp Dec 18 '18 at 19:41
  • Thank you Philipp, I know the execute signature, but how do I mock the function? What I did is to wrap the executed function with in a trait and class that extends it(trait elasticHelper{ def insert(client:ElasticClient, requests: IndexRequest)}). I add to the insert function implicit elasticHelper argument and now I can mock the trait and implicitly send to the insert function my mock implementation. Is this is a workaround or the proper way of mocking? – D. bachar Dec 18 '18 at 20:07
  • I like facades to abstract from APIs that are hard to mock, but looks like elastic4s already has some patterns to do that and these look pretty generic. maybe you don't even need mocks here if you can find an `F[_]` that evaluates the call in a test context. But i have not worked with this library so i'm not sure what that would look like. – Philipp Dec 28 '18 at 00:22

1 Answers1

1

It's not the most pleasant on the eyes, but this should get you started. The important part is to spell out all the implicit paramets and make them explicit when defining the expected calls. I have invented dummy classes to show a minimal example, rather than convolute it with the actual elastic4s stuff.

class BulkResponse
class Response[T]
class ImplicitFoo
abstract class Foo {
  def ex2[T, U](t: T)(implicit foo: ImplicitFoo): Response[U]
}

"A test" can "mock implicit params" in {
  val foo = mock[Foo]
  (foo.ex2[BulkResponse, String](_: BulkResponse)(_: ImplicitFoo)).expects(*, *).returns(new Response[String]).once()
}
Philipp
  • 967
  • 6
  • 16