0

So I'm migrating a small Java codebase to Kotlin just for fun, and I've migrated this Java class:

public class Inputs {
    private String engineURL;
    private Map<String, String> parameters;

    public Inputs(String engineURL, Map<String, String> parameters) {
        this.engineURL = engineURL;
        this.parameters = parameters;
    }

    public String getEngineURL() {
        return engineURL;
    }

    public String getParameter(String key) {
        return parameters.get(key);
    }
}

into this Kotlin representation:

open class Inputs (val engineURL: String, 
                   private val parameters: Map<String, String>) {

    fun getParameter(key: String?): String {
        return parameters["$key"].orEmpty()
    }

}

But now I'm having some trouble with the existing test suite, written in Java. More specifically, I have this piece of unit test that uses Mockito:

@Before
public void setupInputs() {
    inputs = mock(Inputs.class);
    when(inputs.getEngineURL()).thenReturn("http://example.com");
}

and it fails at the when line, saying

org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
   Those methods *cannot* be stubbed/verified.
   Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.

Does anyone know how could I make this work? I've tried creating an actual getter on the Kotlin version (instead of relying on the implicit getter), but got no luck so far.

Thanks a lot!

(in case you're asking yourself why did i start with production code instead of tests, or why don't i use mockito-kotlin, there's no real answer to those questions. like i said, i migrating just for fun and wanted to show other developers in my team how easy it is to have interoperability among languages in real projects)

UPDATE: I noticed if I add when(inputs.getParameter("key")).thenReturn("value") to the same setupInputs() method (before the inputs.getEngineURL()) call), I end up with a NullPointerException at Inputs#getParameter. WTF?!

felipecao
  • 993
  • 1
  • 10
  • 23
  • For the record: the kotlin code here is missing the the getEngineUrl() method. So your example is not a [mcve]. Feel free to update; then I would feel like upvoting your input ;-) – GhostCat Jul 03 '17 at 07:11
  • @GhostCat I'm not sure I follow it, after all `getEngineUrl()` is automatically provided by Kotlin, based on the `val engineURL: String` constructor param, no? – felipecao Jul 04 '17 at 06:43
  • Well, you might have a point there ;-) – GhostCat Jul 04 '17 at 06:44

1 Answers1

1

Nevermind, I got away with both error messages by rewriting the Kotlin version like this:

open class TransformInputs (private val eURL: String, 
                            private val parameters: Map<String, String>) {

    open fun getParameter(key: String?): String {
        return parameters["$key"].orEmpty()
    }

    open fun getBookingEngineURL(): String {
        return eURL
    }

}
felipecao
  • 993
  • 1
  • 10
  • 23
  • You can also avoid making your classes unnecessarily open in Mockito 2: http://hadihariri.com/2016/10/04/Mocking-Kotlin-With-Mockito/ – JK Ly Jul 03 '17 at 07:38
  • Thx @JKLy! I actually considered it, but I didn't want to change too much of my existing codebase just to make it work with Kotlin. My idea was to show the team that using Kotlin was possible with bare minimum changes, so I left out Mockito version out of scope on purpose. – felipecao Jul 04 '17 at 06:45