3

I have an interface that communicates with my presenter who checks whether the fields of a form are valid.

My interface is:

interface MainView {
  fun showMessage(data: LoginEntity)
  fun showEmailError()
  fun showPasswordError()
}

My method in the presenter is like that:

fun sendForm(loginData: LoginDataPresentation, view: MainView) {
   if (isValid()) {
     view.showMessage(mapData(loginData))
   } else if (isValidPassword()) {
     view.showPasswordError()
   } else {
     view.showEmailError()
   }
}

My test class with KotlinTest:

class LoginPresentationKtTest : StringSpec() {

  init {
    "given a bunch of Login Data should be matched successfully" {
       forAll(EmailGenerator(), PasswordGenerator(), { email: String, password: String ->

         val loginData: LoginDataPresentation(email, password)

         val mockMainView = mockMainView()

         sendForm(loginData, mockMainView())

       })
    }
  }

  private fun mockMainView(): MainView {
    //How to mock?????
  }
}

Using the KotlinTest library, is there any way to verify that the call to the showMessage method of the MainView class is done provided that the email and password generated is always correct? Is it possible to use a mock library like mockito?


With the response of the user @mkobit, the following modification can be made using Mockito-Kotlin, with which the test would be as follows:

class LoginPresentationKtTest : StringSpec() {
 init {
   "given a bunch of Login Data should be matched successfully" {
     forAll(EmailGenerator(), PasswordGenerator(), { email: String, password: String ->

       val loginData = LoginDataPresentation(email, password)

       val mockMainView = Mockito.mock(MainView::class.java)

       sendForm(loginData, mockMainView)

       verify(mockMainView).showMessage()
       true
     })
   }
 }
}

At each execution of the loop, it will be checked if the verify () function has been called. If the execution flow is the expected one, it will proceed to the next execution of the loop. If the verify () function fails, an error will occur in the console indicating that the test has failed.

Is there any better solution?

beni
  • 3,019
  • 5
  • 35
  • 55

1 Answers1

0

You mentioned Mockito, so I'll show you can example. I'm going to also use the nhaarman/mockito-kotlin library that makes it more expressive and easier to use in Kotlin.

import com.nhaarman.mockito_kotlin.mock

val mockMainView: MainView = mock()

This is basically equivalent to val mockMainView = Mockito.mock(MainView::class.java) from Mockito. In Kotlin, we can get a more concise and compact code due to some of its features.

If you want to do some stubbing (like return values, exceptions, etc.) you could use the whenever (Mockito.when(T methodCall)) API. See the documentation for details. I'm going to skip that for now.

So, now you would call for method:

sendForm(loginData, mockMainView)

Then, you can perform verification. Using mockito-kotlin method verify (Mockito.verify(T mock)) the behavior.

import com.nhaarman.mockito_kotlin.verify

verify(mockMainView).showPasswordError()
verify(mockMainView).showEmailError()

Using any() (Mockito.any(Class<T> type)) to not just verify method is called with any value.

import com.nhaarman.mockito_kotlin.any

verify(mockMainView).showMessage(any())

There is support for other argument matchers if you want to be more explicit with what is being passed in.

Note that Mockito also supports opt-in mocking of final classes/methods. The example for Gradle would be something like adding a file to src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker with the contents of mock-maker-inline.

References:

  1. Mockito Javadoc
  2. mockito-kotlin Wiki documentation
mkobit
  • 43,979
  • 12
  • 156
  • 150
  • The problem is that the forAll method of the KotlinTest library needs to return a Boolean value in each iteration. We can not use the verify(mockMainView).showMessage(any()) method because it returns Any. – beni Mar 27 '18 at 14:40
  • @beni Got it, I didn't know that. The ugly part would just be adding a `true` to the end of the method body. – mkobit Mar 27 '18 at 16:00
  • Actually @beni you're in luck because in release 3.0.0 of KotlinTest (just last couple of days), then you can use assertAll instead of forAll. It's another property testing method but one that lets you use normal assertions (matchers like shouldBe) instead of enforcing a boolean variable. – sksamuel Mar 31 '18 at 00:04