2016-06-22 18 views

Antwort

5

Machen Sie nur Objekt eine Schnittstelle implementieren, als Sie Objekt mit jeder Mocking-Bibliothek verspotten können. Hier Beispiel Junit + Mockito + Mockito-Kotlin:

import com.nhaarman.mockito_kotlin.mock 
import com.nhaarman.mockito_kotlin.whenever 
import org.junit.Assert.assertEquals 
import org.junit.Test 

object SomeObject : SomeInterface { 
    override fun someFun():String { 
     return "" 
    } 
} 

interface SomeInterface { 
    fun someFun():String 
} 

class SampleTest { 

    @Test 
    fun test_with_mock() { 
     val mock = mock<SomeInterface>() 

     whenever(mock.someFun()).thenReturn("42") 

     val answer = mock.someFun() 

     assertEquals("42", answer) 
    } 
} 

Oder im Falle, wenn Sie wollen Mock SomeObject innen callerFun:

import com.nhaarman.mockito_kotlin.mock 
import com.nhaarman.mockito_kotlin.whenever 
import org.junit.Assert.assertEquals 
import org.junit.Test 

object SomeObject : SomeInterface { 
    override fun someFun():String { 
     return "" 
    } 
} 

class Caller(val someInterface: SomeInterface) { 
    fun callerFun():String { 
     return "Test ${someInterface.someFun()}" 
    } 
} 

// Example of use 
val test = Caller(SomeObject).callerFun() 

interface SomeInterface { 
    fun someFun():String 
} 

class SampleTest { 

    @Test 
    fun test_with_mock() { 
     val mock = mock<SomeInterface>() 
     val caller = Caller(mock) 

     whenever(mock.someFun()).thenReturn("42") 

     val answer = caller.callerFun() 

     assertEquals("Test 42", answer) 
    } 
} 
+0

Das sieht wie ein Anti-Muster ... Man sollte keine zusätzlichen Klassen/Schnittstellen im Hauptcode nur für den Zweck des Testens erstellen! – Kerooker

+0

Keine zusätzlichen Klassen, nur Schnittstellen. Und Sie sollten es tun, weil dies die beste Vorgehensweise für das Testen auf JVM ist. – IRus

0

Kurz vor der Manipulation von Byte-Code ist die Antwort nein, es sei denn, Sie sind bereit und in der Lage, den Code zu ändern. Der einfachste Weg (und die Art und Weise, wie ich es empfehlen würde), 's Call to SomeObject.someFun() zu verspotten, ist es, einen Weg zu bieten, um ein Mock-Objekt zu rutschen.

z.B.

object SomeObject { 
    fun someFun() {} 
} 

fun callerFun() { 
    _callerFun { SomeObject.someFun() } 
} 

internal inline fun _callerFun(caller:() -> Unit) { 
    caller() 
} 

Die Idee hier ist, etwas zu ändern, das Sie bereit sind zu ändern. Wenn Sie sicher sind, dass Sie eine Singleton- und eine Top-Level-Funktion für diesen Singleton verwenden möchten, können Sie die Implementierung der Top-Level-Funktion testen, ohne die öffentliche Signatur zu ändern, indem Sie die Implementierung in eine internal-Funktion verschieben das erlaubt, einen Schein zu rutschen.

2

Es ist eine sehr schöne neue spöttische Bibliothek für Kotlin. Es heißt Mockk.

Es wurde heute auf Version 1.7 aktualisiert, und es ermöglicht Ihnen, Objekte zu verspotten, genau so, wie Sie es wünschen.

Wie es in der Dokumentation:


Objekte können Mocks folgende Art und Weise transformiert werden:

object MockObj { 
    fun add(a: Int, b: Int) = a + b 
} 

objectMockk(MockObj).use { 
    assertEquals(3, MockObj.add(1, 2)) 

    every { MockObj.add(1, 2) } returns 55 

    assertEquals(55, MockObj.add(1, 2)) 
} 

Trotz Kotlin Sprachgrenzen können Sie neue Instanzen von Objekten erstellen, wenn Testlogik benötigt das:

val newObjectMock = mockk<MockObj>() 
2

Sie können Objekt ohne zusätzliche Bibliothek verspotten, von Klasse mit Delegierten.

Hier ist mein Vorschlag

val someObjectDelegate : SomeInterface? = null 

object SomeObject: by someObjectDelegate ?: SomeObjectImpl 

object SomeObjectImpl : SomeInterface { 

    fun someFun() { 
     println("SomeObjectImpl someFun called") 
    } 
} 

interface SomeInterface { 
    fun someFun() 
} 

In Ihren Tests Sie Delegatobjekt festlegen, die das Verhalten ändern, sonst wird es verwenden, es tatsächliche Umsetzung ist.

@Beofre 
fun setUp() { 
    someObjectDelegate = object : SomeInterface { 
     fun someFun() { 
      println("Mocked function") 
     } 
    } 
    // Will call method from your delegate 
    SomeObject.someFun() 
} 

Natürlich Namen sind oben schlecht, aber im Interesse eines Beispiels zeigt es den Zweck.

Nachdem SomeObject initialisiert ist Delegate alle Funktionen behandelt.
Mehr können Sie in offiziellen finden documentation