FutureShocked
FutureShocked

Reputation: 888

Is there a way to verify that a top-level function passed as a dependency to a class has been called during testing?

I have a class that receives a function allowing it to display things on the UI during a failure case. What's the best way that I can verify that the function is called in my test?

MyClass(private val uiPrinter: (String) -> Unit) {
    fun foo() {
        // do some stuff
        uiPrinter("printing from foo!")
        // do some more stuff 
    }
}

MyClassTest() {
    val testUiPrinter: (String) -> Unit = { System.out.println(it) }

    @Test
    fun uiPrinterIsInvoked() {
        val myClass = MyClass(testUiPrinter)
        myClass.foo()
        // can I verify that testUiPrinter has been invoked?
    }
}

Upvotes: 0

Views: 1775

Answers (2)

FutureShocked
FutureShocked

Reputation: 888

This can be achieved by mocking the higher-order function as higher-order functions are objects unless inlined.

@Mock
val testUiPrinter: (String) -> Unit

@Test
fun uiPrinterIsInvoked() {
    val myClass = MyClass(testUiPrinter)
    myClass.foo()
    verify(testUiPrinter).invoke("Printing from foo!")
}

Upvotes: 0

M. Palsich
M. Palsich

Reputation: 1818

You may want to check out the Model-View-Presenter architecture. Its purpose is to hide the Android framework behind an abstract View interface which a purely Java Presenter can interact with. In your example:

interface ViewInterface {
  fun printError(error: String)
}


class MyPresenter(private val view: ViewInterface) {
  fun foo() {
    // do some stuff (testable stuff)
    view.printError("Printing from foo()!")
    // do some more (testable) stuff
  }
} 

class MyPresenterTest() { // Test using Mockito to mock the abstract view
    private val view = mock(ViewInterface::class.java)
    private val presenter = MyPresenter(view)

    @Test
    fun printsError() {
        // set up preconditions

        presenter.foo()

        verify(view).printError("Printing from foo()!")
    }
}

Your concrete view will generally be an Android Activity, Fragment, or View which implements the view interface. Notice MyPresenter only expects the abstract view and does not need knowledge of the framework-dependent operations.

class MyActivity : Activity(), ViewInterface {
    // ...

    override fun printError(error: String) {
        textView.text = error // For example
    }
    // ...
}

Upvotes: 1

Related Questions