0
votes

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?!

1
For the record: the kotlin code here is missing the the getEngineUrl() method. So your example is not a minimal reproducible example. Feel free to update; then I would feel like upvoting your input ;-) - GhostCat
@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
Well, you might have a point there ;-) - GhostCat

1 Answers

1
votes

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
    }

}