Alles, was Sie anfangen müssen, ist nur eine Abhängigkeit zur MockK -Bibliothek hinzuzufügen.
| Ansatz | Anweisung |
|---|---|
![]() | Testimplementation "io.mockk: mockk: $ {mockkversion}"
|
(Kotlin DSL) | Testimplementation ("io.mockk: mockk: $ {mockkversion}") |
![]() | <De vorangehen>
<GruppeId> io.mockk </Groupid>
<artifactid> mockk-jvm </artifactid>
<version> $ {MockKversion} </Version>
<Schops> Test </Scope>
</abhängig>
|
Testimplementation "io.mockk: mockk-android: $ {mockkversion}"
Testimplementation "io.mockk: Mockk-Agent: $ {MockKversion}"
| |
AndroidTestImplementation "io.mockk: Mockk-Android: $ {MockKversion}"
AndroidTestImplementation "io.mockk: Mockk-Agent: $ {MockKversion}"
|
Einfachste Beispiel. Standardmäßig sind Mocks streng, sodass Sie ein gewisses Verhalten vornehmen müssen.
val car = mockk< Car >()
every { car.drive( Direction . NORTH ) } returns Outcome . OK
car.drive( Direction . NORTH ) // returns OK
verify { car.drive( Direction . NORTH ) }
confirmVerified(car)Weitere detailliertere Beispiele finden Sie im Abschnitt "Features".
Von Version 1.13.0 Mockk unterstützt Kotlin 1.4 und höher
mockkStatic funktionieren möglicherweise nicht auf JDK 16+; InaccessibleObjectException / IllegalAccessException : Lesen Sie hier mehrInhaltsverzeichnis:
Überprüfen Sie die Artikelreihe "Mocking is No Rocket Science" bei KT. Akademie beschreibt Mockk aus den Grundlagen, sich zu verspotten, bis zur Beschreibung aller erweiterten Funktionen.
Grundlagen
Erwartete Verhaltens- und Verhaltensprüfung
Mockk -Funktionen
Mockk Advanced Features
Testen Sie Quarkus mit Kotlin, Junit und Mockk
Mockks schwarze Magie entwirren (en, Übersetzung)
Mockk -Leitfaden
"Kotlin -Unit -Test mit Mockk" von Marco Cattaneo
(Video) Verwenden Sie in MockK Verify, um Funktionsaufrufe zum verspotteten Objekt zu validieren
Testen mit Mockk bezahlte Kurs auf Raywenderlich.com
TDD für Android Video Tutorial Teil 1, Teil 2 von Ryan Kay
(Video) Android Developer Live -Codierung Nr. 13: Unit -Tests mit Mockk, Coroutines, testgetriebene Entwicklung
KOTLINCONF 2018 - Best Practices für Unit -Tests in Kotlin von Philipp Hauer
Kotlin-Fullstack-Sample verwendet das Mockk-Projekt mit Tests
Dzone -Artikel
Habrahabr Artikel (Ru)
Spott in Kotlin mit Mockk - Yannick de Turck
Sie können Anmerkungen verwenden, um die Erstellung von Scheinobjekten zu vereinfachen:
class TrafficSystem {
lateinit var car1 : Car
lateinit var car2 : Car
lateinit var car3 : Car
}
class CarTest {
@MockK
lateinit var car1 : Car
@RelaxedMockK
lateinit var car2 : Car
@MockK(relaxUnitFun = true )
lateinit var car3 : Car
@SpyK
var car4 = Car ()
@InjectMockKs
var trafficSystem = TrafficSystem ()
@Before
fun setUp () = MockKAnnotations . init ( this , relaxUnitFun = true ) // turn relaxUnitFun on for all mocks
@Test
fun calculateAddsValues1 () {
// ... use car1, car2, car3 and car4
}
} Die Injektion versucht zuerst, Eigenschaften mit Namen, dann nach Klasse oder Superklasse zu entsprechen. Überprüfen Sie den Parameter lookupType zur Anpassung.
Eigenschaften werden injiziert, auch wenn private angewendet wird. Konstrukteure für die Injektion werden aus der größten Anzahl von Argumenten auf den niedrigsten ausgewählt.
@InjectMockKs standardmäßig injiziert nur lateinit var s oder var s, die nicht zugewiesen werden. Um dies zu ändern, verwenden Sie overrideValues = true . Dies würde den Wert zuweisen, auch wenn er bereits irgendwie initialisiert wird. Verwenden Sie zum Inject val S injectImmutable = true . Verwenden Sie für eine kürzere Notation @OverrideMockKs , die standardmäßig das Gleiche wie @InjectMockKs , aber diese beiden Flags einschalten.
Junit 4 enthält eine regelbasierte API, um eine Automatisierung nach dem Testlebenszyklus zu ermöglichen. Mockk enthält eine Regel, die dies verwendet, um Ihre Mocks aufzubauen, ohne MockKAnnotations.init(this) manuell aufzurufen. Beispiel:
class CarTest {
@get:Rule
val mockkRule = MockKRule ( this )
@MockK
lateinit var car1 : Car
@RelaxedMockK
lateinit var car2 : Car
@Test
fun something () {
every { car1.drive() } just runs
every { car2.changeGear(any()) } returns true
// etc
}
} In JUNIT5 können Sie mit MockKExtension Ihre Mocks initialisieren.
@ExtendWith( MockKExtension :: class )
class CarTest {
@MockK
lateinit var car1 : Car
@RelaxedMockK
lateinit var car2 : Car
@MockK(relaxUnitFun = true )
lateinit var car3 : Car
@SpyK
var car4 = Car ()
@Test
fun calculateAddsValues1 () {
// ... use car1, car2, car3 and car4
}
} Zusätzlich wird die Möglichkeit hinzugefügt, @MockK und @RelaxedMockK für Testfunktionsparameter zu verwenden:
@Test
fun calculateAddsValues1 (@MockK car1 : Car , @RelaxedMockK car2 : Car ) {
// ... use car1 and car2
} Schließlich ruft diese Erweiterung unmockkAll und clearAllMocks in einem @AfterAll -Rückruf auf, um sicherzustellen, dass Ihre Testumgebung nach jeder Ausführung der Testklasse sauber ist. Sie können dieses Verhalten deaktivieren, indem Sie die @MockKExtension.KeepMocks -Annotation zu Ihrer Klasse oder global hinzufügen, indem Sie die mockk.junit.extension.keepmocks=true -Eigenschaft festlegen. (Da v1.13.11) Alternativ, da clearAllMocks standardmäßig ( currentThreadOnly=false ) nicht mit mockk.junit.extension.requireParallelTesting=true -Sicherheit ist, können Sie die MockKExtension.RequireParallelTesting @AfterAll . Wenn clearAllMocks explizit aufgerufen wird, können Sie clearAllMocks(currentThreadOnly = true) liefern, damit nur Mocks im selben Thread (da V1.13.12) gelöscht.
Sie können sicherstellen, dass alle stubigen Methoden tatsächlich überprüft werden, indem Sie auch Ihre Testklasse mit @MockKExtension.ConfirmVerification annotieren.
Dies wird nach jedem Test in allen Mocks intern confirmVerified , um sicherzustellen, dass keine unnötigen Stubbings vorhanden sind.
Bitte beachten Sie, dass dieses Verhalten möglicherweise nicht wie erwartet funktioniert, wenn Sie Tests in Ihrer IDE durchführen, da es Gradle ist, die sich um die Behandlung der Ausnahme kümmert, wenn diese confirmVerified Anrufe fehlschlagen.
Sie können sicherstellen, dass alle stubigen Methoden mindestens einmal nützlich sind, indem Sie auch Ihre Testklasse mit @MockKExtension.CheckUnnecessaryStub annotieren.
Dies wird nach jedem Test intern auf allen Mocks checkUnnecessaryStub , um sicherzustellen, dass keine unnötigen Stubbings vorhanden sind.
Mit Spione können Sie Mocks und echte Objekte mischen.
val car = spyk( Car ()) // or spyk<Car>() to call the default constructor
car.drive( Direction . NORTH ) // returns whatever the real function of Car returns
verify { car.drive( Direction . NORTH ) }
confirmVerified(car)Anmerkung 1: Das Spionageobjekt ist eine Kopie des übergebenen Objekts. Anmerkung 2: Es gibt ein bekanntes Problem, wenn ein Spion mit einer Suspendierungsfunktion verwendet wird: #554
Ein relaxed mock ist das Schein, das einen einfachen Wert für alle Funktionen zurückgibt. Auf diese Weise können Sie das Verhalten für jeden Fall überspringen, während Sie immer noch Dinge stützen, die Sie benötigen. Als Referenztypen werden gekettete Mocks zurückgegeben.
val car = mockk< Car >(relaxed = true )
car.drive( Direction . NORTH ) // returns null
verify { car.drive( Direction . NORTH ) }
confirmVerified(car)Hinweis: Entspannte Verspottung funktioniert schlecht mit generischen Rückgabetypen. In diesem Fall wird normalerweise eine Ausnahme in der Klasse besetzt. Entscheiden Sie sich für manuell im Fall eines generischen Rückgabetyps für manuell.
Problemumgehung:
val func = mockk < () -> Car > (relaxed = true ) // in this case invoke function has generic return type
// this line is workaround, without it the relaxed mock would throw a class cast exception on the next line
every { func() } returns Car () // or you can return mockk() for example
func() Manchmal müssen Sie einige Funktionen beachten, aber dennoch die eigentliche Methode für andere oder bestimmte Argumente aufrufen. Dies ist möglich, indem callOriginal() an answers weitergegeben wird, die sowohl für entspannte als auch für nicht geraxe Mocke geeignet sind.
class Adder {
fun addOne ( num : Int ) = num + 1
}
val adder = mockk< Adder >()
every { adder.addOne(any()) } returns - 1
every { adder.addOne( 3 ) } answers { callOriginal() }
assertEquals( - 1 , adder.addOne( 2 ))
assertEquals( 4 , adder.addOne( 3 )) // original function is called Wenn Sie möchten, dass Unit entspannt werden, können Sie relaxUnitFun = true als Argument für die mockk -Funktion, @MockK Annotation oder MockKAnnotations.init -Funktion verwenden.
Funktion:
mockk< ClassBeingMocked >(relaxUnitFun = true )Anmerkung:
@MockK(relaxUnitFun = true )
lateinit var mock1 : ClassBeingMocked
init {
MockKAnnotations . init ( this )
}Mockkannotations.init:
@MockK
lateinit var mock2 : ClassBeingMocked
init {
MockKAnnotations . init ( this , relaxUnitFun = true )
}Objekte können auf folgende Weise in Mocke verwandelt werden:
object ObjBeingMocked {
fun add ( a : Int , b : Int ) = a + b
}
mockkObject( ObjBeingMocked ) // applies mocking to an Object
assertEquals( 3 , ObjBeingMocked .add( 1 , 2 ))
every { ObjBeingMocked .add( 1 , 2 ) } returns 55
assertEquals( 55 , ObjBeingMocked .add( 1 , 2 )) Verwenden Sie zur Rückkehr, verwenden Sie unmockkObject oder unmockkAll (destruktiver: Objekt-, statische und Konstruktor -Mocks).
@Before
fun beforeTests () {
mockkObject( ObjBeingMocked )
every { ObjBeingMocked .add( 1 , 2 ) } returns 55
}
@Test
fun willUseMockBehaviour () {
assertEquals( 55 , ObjBeingMocked .add( 1 , 2 ))
}
@After
fun afterTests () {
unmockkObject( ObjBeingMocked )
// or unmockkAll()
}Trotz der Kotlin -Sprachbeschränkungen können Sie bei Bedarf neue Instanzen von Objekten erstellen, indem Sie die Logik testen:
val newObjectMock = mockk< ObjBeingMocked >() Manchmal braucht man einen Schein einer willkürlichen Klasse. Verwenden Sie in diesen Fällen mockkClass .
val car = mockkClass( Car :: class )
every { car.drive( Direction . NORTH ) } returns Outcome . OK
car.drive( Direction . NORTH ) // returns OK
verify { car.drive( Direction . NORTH ) } Aufzüge können mit mockkObject verspottet werden:
enum class Enumeration ( val goodInt : Int ) {
CONSTANT ( 35 ),
OTHER_CONSTANT ( 45 );
}
mockkObject( Enumeration . CONSTANT )
every { Enumeration . CONSTANT .goodInt } returns 42
assertEquals( 42 , Enumeration . CONSTANT .goodInt)Manchmal, insbesondere im Code, den Sie nicht besitzen, müssen Sie neu erstellte Objekte verspotten. Zu diesem Zweck werden folgende Konstrukte bereitgestellt:
class MockCls {
fun add ( a : Int , b : Int ) = a + b
}
mockkConstructor( MockCls :: class )
every { anyConstructed< MockCls >().add( 1 , 2 ) } returns 4
assertEquals( 4 , MockCls ().add( 1 , 2 )) // note new object is created
verify { anyConstructed< MockCls >().add( 1 , 2 ) } Die Grundidee ist, dass Objekte kurz nach dem Konstruktor der verspotteten Klasse (jeden von ihnen) zum constructed mock werden.
Das Verspottungsverhalten eines solchen Scheins ist mit dem prototype mock verbunden, der mit anyConstructed<MockCls>() gekennzeichnet ist.
Es gibt eine Instanz pro Klasse eines solchen prototype mock . Die Anrufaufzeichnung kommt auch mit dem prototype mock vor.
Wenn kein Verhalten für die Funktion angegeben ist, wird die ursprüngliche Funktion ausgeführt.
Falls eine Klasse mehr als einen Konstruktor hat, kann jeder separat verspottet werden:
class MockCls ( private val a : Int = 0 ) {
constructor (x : String ) : this (x.toInt())
fun add ( b : Int ) = a + b
}
mockkConstructor( MockCls :: class )
every { constructedWith< MockCls >().add( 1 ) } returns 2
every {
constructedWith< MockCls >( OfTypeMatcher < String >( String :: class )).add( 2 ) // Mocks the constructor which takes a String
} returns 3
every {
constructedWith< MockCls >( EqMatcher ( 4 )).add(any()) // Mocks the constructor which takes an Int
} returns 4
assertEquals( 2 , MockCls ().add( 1 ))
assertEquals( 3 , MockCls ( " 2 " ).add( 2 ))
assertEquals( 4 , MockCls ( 4 ).add( 7 ))
verify {
constructedWith< MockCls >().add( 1 )
constructedWith< MockCls >( " 2 " ).add( 2 )
constructedWith< MockCls >( EqMatcher ( 4 )).add( 7 )
} Beachten Sie, dass in diesem Fall ein prototype mock für jede Reihe von Argumentatoren erstellt wird, die an constructedWith wurden.
Sie können sowohl regelmäßige Argumente als auch Matcher mischen:
val car = mockk< Car >()
every {
car.recordTelemetry(
speed = more( 50 ),
direction = Direction . NORTH , // here eq() is used
lat = any(),
long = any()
)
} returns Outcome . RECORDED
car.recordTelemetry( 60 , Direction . NORTH , 51.1377382 , 17.0257142 )
verify { car.recordTelemetry( 60 , Direction . NORTH , 51.1377382 , 17.0257142 ) }
confirmVerified(car)Sie können Anrufketten stummeln:
val car = mockk< Car >()
every { car.door( DoorType . FRONT_LEFT ).windowState() } returns WindowState . UP
car.door( DoorType . FRONT_LEFT ) // returns chained mock for Door
car.door( DoorType . FRONT_LEFT ).windowState() // returns WindowState.UP
verify { car.door( DoorType . FRONT_LEFT ).windowState() }
confirmVerified(car) Hinweis: Wenn der Rückgabetyp der Funktion generisch ist, ist die Informationen zum tatsächlichen Typ verschwunden.
Um verkettete Anrufe zum Laufen zu bringen, sind zusätzliche Informationen erforderlich.
Die meiste Zeit wird der Rahmen die Ausnahme der Besetzung durchführen und autohinting bewirken.
Wenn es ausdrücklich erforderlich ist, verwenden Sie hint , bevor Sie den nächsten Anruf tätigen.
every { obj.op2( 1 , 2 ).hint( Int :: class ).op1( 3 , 4 ) } returns 5Aus Version 1.9.1 können Mocks in Hierarchien gekettet werden:
interface AddressBook {
val contacts : List < Contact >
}
interface Contact {
val name : String
val telephone : String
val address : Address
}
interface Address {
val city : String
val zip : String
}
val addressBook = mockk< AddressBook > {
every { contacts } returns listOf (
mockk {
every { name } returns " John "
every { telephone } returns " 123-456-789 "
every { address.city } returns " New-York "
every { address.zip } returns " 123-45 "
},
mockk {
every { name } returns " Alex "
every { telephone } returns " 789-456-123 "
every { address } returns mockk {
every { city } returns " Wroclaw "
every { zip } returns " 543-21 "
}
}
)
} Sie können ein Argument für einen CapturingSlot oder MutableList erfassen.
CapturingSlot wird normalerweise über die Werksmethode slot<T : Any?>() Erstellt und ist möglich, nullbare und nicht nullbare Typen zu erfassen. MutableList soll während des Tests mehrere Werte erfassen.
enum class Direction { NORTH , SOUTH }
enum class RecordingOutcome { RECORDED }
enum class RoadType { HIGHWAY }
class Car {
fun recordTelemetry ( speed : Double , direction : Direction , roadType : RoadType ? ): RecordingOutcome {
TODO ( " not implement for showcase " )
}
}
val car = mockk< Car >()
// allow to capture parameter with non nullable type `Double`
val speedSlot = slot< Double >()
// allow to capture parameter with nullable type `RoadType`
val roadTypeSlot = slot< RoadType ?>()
val list = mutableListOf< Double >()
every {
car.recordTelemetry(
speed = capture(speedSlot), // makes mock match calls with any value for `speed` and record it in a slot
direction = Direction . NORTH , // makes mock and capturing only match calls with specific `direction`. Use `any()` to match calls with any `direction`
roadType = captureNullable(roadTypeSlot), // makes mock match calls with any value for `roadType` and record it in a slot
)
} answers {
println ( " Speed: ${speedSlot.captured} , roadType: ${roadTypeSlot.captured} " )
RecordingOutcome . RECORDED
}
every {
car.recordTelemetry(
speed = capture(list),
direction = Direction . SOUTH ,
roadType = captureNullable(roadTypeSlot),
)
} answers {
println ( " Speed: ${list} , roadType: ${roadTypeSlot.captured} " )
RecordingOutcome . RECORDED
}
car.recordTelemetry(speed = 15.0 , direction = Direction . NORTH , null ) // prints Speed: 15.0, roadType: null
car.recordTelemetry(speed = 16.0 , direction = Direction . SOUTH , RoadType . HIGHWAY ) // prints Speed: [16.0], roadType: HIGHWAY
verifyOrder {
car.recordTelemetry(speed = or ( 15.0 , 16.0 ), direction = any(), roadType = null )
car.recordTelemetry(speed = 16.0 , direction = any(), roadType = RoadType . HIGHWAY )
}
confirmVerified(car) Sie können die Anrufanzahl mit den atLeast atMost oder exactly Parametern überprüfen:
val car = mockk< Car >(relaxed = true )
car.accelerate(fromSpeed = 10 , toSpeed = 20 )
car.accelerate(fromSpeed = 10 , toSpeed = 30 )
car.accelerate(fromSpeed = 20 , toSpeed = 30 )
// all pass
verify(atLeast = 3 ) { car.accelerate(allAny()) }
verify(atMost = 2 ) { car.accelerate(fromSpeed = 10 , toSpeed = or ( 20 , 30 )) }
verify(exactly = 1 ) { car.accelerate(fromSpeed = 10 , toSpeed = 20 ) }
verify(exactly = 0 ) { car.accelerate(fromSpeed = 30 , toSpeed = 10 ) } // means no calls were performed
confirmVerified(car) Oder Sie können verifyCount verwenden:
val car = mockk< Car >(relaxed = true )
car.accelerate(fromSpeed = 10 , toSpeed = 20 )
car.accelerate(fromSpeed = 10 , toSpeed = 30 )
car.accelerate(fromSpeed = 20 , toSpeed = 30 )
// all pass
verifyCount {
( 3 .. 5 ) * { car.accelerate(allAny(), allAny()) } // same as verify(atLeast = 3, atMost = 5) { car.accelerate(allAny(), allAny()) }
1 * { car.accelerate(fromSpeed = 10 , toSpeed = 20 ) } // same as verify(exactly = 1) { car.accelerate(fromSpeed = 10, toSpeed = 20) }
0 * { car.accelerate(fromSpeed = 30 , toSpeed = 10 ) } // same as verify(exactly = 0) { car.accelerate(fromSpeed = 30, toSpeed = 10) }
}
confirmVerified(car)verifyAll prüft, dass alle Anrufe stattgefunden haben, ohne ihre Bestellung zu überprüfen.verifySequence , ob die Aufrufe in einer bestimmten Reihenfolge aufgetreten sind.verifyOrder , ob Anrufe in einer bestimmten Reihenfolge überprüft werden.wasNot Called überprüft, dass der Mock (oder die Liste der Mocks) überhaupt nicht gerufen wurde. class MockedClass {
fun sum ( a : Int , b : Int ) = a + b
}
val obj = mockk< MockedClass >()
val slot = slot< Int >()
every {
obj.sum(any(), capture(slot))
} answers {
1 + firstArg< Int >() + slot.captured
}
obj.sum( 1 , 2 ) // returns 4
obj.sum( 1 , 3 ) // returns 5
obj.sum( 2 , 2 ) // returns 5
verifyAll {
obj.sum( 1 , 3 )
obj.sum( 1 , 2 )
obj.sum( 2 , 2 )
}
verifySequence {
obj.sum( 1 , 2 )
obj.sum( 1 , 3 )
obj.sum( 2 , 2 )
}
verifyOrder {
obj.sum( 1 , 2 )
obj.sum( 2 , 2 )
}
val obj2 = mockk< MockedClass >()
val obj3 = mockk< MockedClass >()
verify {
listOf (obj2, obj3) wasNot Called
}
confirmVerified(obj) Um zu überprüfen, ob alle Anrufe durch verify... Constructs verifiziert wurden, können Sie confirmVerified verwenden:
confirmVerified(mock1, mock2) Es ist nicht sehr sinnvoll, es für verifySequence und verifyAll zu verwenden, da diese Überprüfungsmethoden bereits alle Aufrufe mit Verifizierung abdecken.
Es wird eine Ausnahme ausgelöst, wenn einige Anrufe ohne Überprüfung übrig sind.
Einige Anrufe können von dieser Bestätigung ausgeschlossen werden. Weitere Informationen finden Sie im nächsten Abschnitt.
val car = mockk< Car >()
every { car.drive( Direction . NORTH ) } returns Outcome . OK
every { car.drive( Direction . SOUTH ) } returns Outcome . OK
car.drive( Direction . NORTH ) // returns OK
car.drive( Direction . SOUTH ) // returns OK
verify {
car.drive( Direction . SOUTH )
car.drive( Direction . NORTH )
}
confirmVerified(car) // makes sure all calls were covered with verificationDa Clean & Wardable Testcode keinen unnötigen Code erfordert, können Sie sicherstellen, dass keine unnötigen Stubs vorhanden sind.
checkUnnecessaryStub(mock1, mock2)Es wird eine Ausnahme ausgelöst, wenn es einige deklarierte Anrufe auf die Mocks gibt, die nicht vom getesteten Code verwendet werden. Dies kann passieren, wenn Sie einige wirklich unnötige Stubs deklariert haben oder wenn der getestete Code keinen erwarteten anruft.
Um unwichtige Anrufe von der Aufzeichnung auszuschließen, können Sie excludeRecords verwenden:
excludeRecords { mock.operation(any(), 5 ) } Alle passenden Anrufe werden von der Aufzeichnung ausgeschlossen. Dies kann nützlich sein, wenn Sie erschöpfende Überprüfung verwenden: verifyAll , verifySequence oder confirmVerified .
val car = mockk< Car >()
every { car.drive( Direction . NORTH ) } returns Outcome . OK
every { car.drive( Direction . SOUTH ) } returns Outcome . OK
excludeRecords { car.drive( Direction . SOUTH ) }
car.drive( Direction . NORTH ) // returns OK
car.drive( Direction . SOUTH ) // returns OK
verify {
car.drive( Direction . NORTH )
}
confirmVerified(car) // car.drive(Direction.SOUTH) was excluded, so confirmation is fine with only car.drive(Direction.NORTH) Um gleichzeitige Vorgänge zu überprüfen, können Sie timeout = xxx verwenden:
mockk< MockCls > {
every { sum( 1 , 2 ) } returns 4
Thread {
Thread .sleep( 2000 )
sum( 1 , 2 )
}.start()
verify(timeout = 3000 ) { sum( 1 , 2 ) }
}Dies wird warten, bis einer von zwei folgenden Zuständen verabschiedet wird oder die Auszeit erreicht ist.
Wenn eine Funktion Unit zurückgibt, können Sie das justRun -Konstrukt verwenden:
class MockedClass {
fun sum ( a : Int , b : Int ): Unit {
println (a + b)
}
}
val obj = mockk< MockedClass >()
justRun { obj.sum(any(), 3 ) }
obj.sum( 1 , 1 )
obj.sum( 1 , 2 )
obj.sum( 1 , 3 )
verify {
obj.sum( 1 , 1 )
obj.sum( 1 , 2 )
obj.sum( 1 , 3 )
} Andere Möglichkeiten zum Schreiben von justRun { obj.sum(any(), 3) } :
every { obj.sum(any(), 3) } just Runsevery { obj.sum(any(), 3) } returns Unitevery { obj.sum(any(), 3) } answers { Unit }Um Coroutinen zu verspotten, müssen Sie der Unterstützungsbibliothek eine weitere Abhängigkeit hinzufügen.
| Gradle |
|---|
Testimplementation "org.jetbrains.kotlinx: kotlinx-coroutines-core: xx" |
| Maven |
|---|
<De vorangehen>
<gruppeID> org.jetbrains.kotlinx </Groupid>
<artifactid> kotlinx-coroutines-core </artifactid>
<version> xx </Version>
<Schops> Test </Scope>
</abhängig> |
Anschließend können Sie coEvery , coVerify , coMatch , coRun coAssert coAnswers -oder coInvoke -Funktionsfunktionen verwenden.
val car = mockk< Car >()
coEvery { car.drive( Direction . NORTH ) } returns Outcome . OK
car.drive( Direction . NORTH ) // returns OK
coVerify { car.drive( Direction . NORTH ) } Und um eine nie zurückgekehrte suspend -Funktion zu simulieren, können Sie coJustAwait verwenden:
runTest {
val car = mockk< Car >()
coJustAwait { car.drive(any()) } // car.drive(...) will never return
val job = launch( UnconfinedTestDispatcher ()) {
car.drive( Direction . NORTH )
}
coVerify { car.drive( Direction . NORTH ) }
job.cancelAndJoin() // Don't forget to cancel the job
}Hinweis: Es gibt ein bekanntes Problem, wenn ein Spion mit einer Suspendierungsfunktion verwendet wird: #554
Mit Kotlin können Sie Funktionen deklarieren, die nicht zu einer Klasse oder einem Objekt angehören, die als Funktionen auf höchstem Niveau bezeichnet werden. Diese Anrufe werden in statische Methoden in jvm -Umgebungen übersetzt, und es wird eine spezielle Java -Klasse generiert, um die Funktionen zu halten. Diese Funktionen auf oberster Ebene können mit mockkStatic verspottet werden. Sie müssen nur die Funktion importieren und eine Referenz als Argument übergeben:
import com.cars.buildCar
val testCar = Car ()
mockkStatic(::buildCar)
every { buildCar() } returns testCar
assertEquals(testCar, buildCar())
verify { buildCar() } Wenn Sie eine Funktion verspotten, werden vorhandene Mocks anderer in derselben Datei deklarierter Funktionen gelöscht, was dem Aufrufen von clearStaticMockk in der generierten umschließenden Klasse entspricht.
In Kotlin gibt es drei Arten von Erweiterungsfunktionen:
Für ein Objekt oder eine Klasse können Sie Erweiterungsfunktionen verspotten, indem Sie ein reguläres mockk erstellen:
data class Obj ( val value : Int )
class Ext {
fun Obj. extensionFunc () = value + 5
}
with (mockk< Ext >()) {
every {
Obj ( 5 ).extensionFunc()
} returns 11
assertEquals( 11 , Obj ( 5 ).extensionFunc())
verify {
Obj ( 5 ).extensionFunc()
}
} Um modulweite Erweiterungsfunktionen zu verspotten, müssen Sie mockkStatic(...) mit dem Klassennamen des Moduls als Argument erstellen. Zum Beispiel "pkg.filekt" für File.kt im pkg -Paket.
data class Obj ( val value : Int )
// declared in File.kt ("pkg" package)
fun Obj. extensionFunc () = value + 5
mockkStatic( " pkg.FileKt " )
every {
Obj ( 5 ).extensionFunc()
} returns 11
assertEquals( 11 , Obj ( 5 ).extensionFunc())
verify {
Obj ( 5 ).extensionFunc()
} In jvm -Umgebungen können Sie den Klassennamen durch eine Funktionsreferenz ersetzen:
mockkStatic( Obj ::extensionFunc) Beachten Sie, dass dies die gesamte pkg.FileKt -Klasse verspottet und nicht nur extensionFunc .
Diese Syntax gilt auch für Erweiterungseigenschaften:
val Obj .squareValue get() = value * value
mockkStatic( Obj ::squareValue) Wenn @JvmName verwendet wird, geben Sie ihn als Klassenname an.
Khttp.kt:
@file:JvmName( " KHttp " )
package khttp
// ... KHttp code Testcode:
mockkStatic( " khttp.KHttp " ) Manchmal müssen Sie ein bisschen mehr wissen, um eine Erweiterungsfunktion zu verspotten. Zum Beispiel hat die Erweiterungsfunktionsdatei.endswith File.endsWith() einen völlig unvorhersehbaren classname :
mockkStatic( " kotlin.io.FilesKt__UtilsKt " )
every { File ( " abc " ).endsWith(any< String >()) } returns true
println ( File ( " abc " ).endsWith( " abc " )) Dies ist ein Standard -Kotlin -Verhalten, das möglicherweise unvorhersehbar ist. Verwenden Sie Tools -> Kotlin -> Kotlin .class Tools -> Kotlin -> Show Kotlin Bytecode oder überprüfen Sie die Dateien im JAR -Archiv, um solche Namen zu erkennen.
Aus Version 1.9.1 ist eine erweiterte Handhabung von Vararg möglich:
interface ClsWithManyMany {
fun manyMany ( vararg x : Any ): Int
}
val obj = mockk< ClsWithManyMany >()
every { obj.manyMany( 5 , 6 , * varargAll { it == 7 }) } returns 3
println (obj.manyMany( 5 , 6 , 7 )) // 3
println (obj.manyMany( 5 , 6 , 7 , 7 )) // 3
println (obj.manyMany( 5 , 6 , 7 , 7 , 7 )) // 3
every { obj.manyMany( 5 , 6 , * anyVararg(), 7 ) } returns 4
println (obj.manyMany( 5 , 6 , 1 , 7 )) // 4
println (obj.manyMany( 5 , 6 , 2 , 3 , 7 )) // 4
println (obj.manyMany( 5 , 6 , 4 , 5 , 6 , 7 )) // 4
every { obj.manyMany( 5 , 6 , * varargAny { nArgs > 5 }, 7 ) } returns 5
println (obj.manyMany( 5 , 6 , 4 , 5 , 6 , 7 )) // 5
println (obj.manyMany( 5 , 6 , 4 , 5 , 6 , 7 , 7 )) // 5
every {
obj.manyMany( 5 , 6 , * varargAny {
if (position < 3 ) it == 3 else it == 4
}, 7 )
} returns 6
println (obj.manyMany( 5 , 6 , 3 , 4 , 7 )) // 6
println (obj.manyMany( 5 , 6 , 3 , 4 , 4 , 7 )) // 6Wenn Sie private Funktionen verspotten müssen, können Sie dies über einen dynamischen Anruf tun.
class Car {
fun drive () = accelerate()
private fun accelerate () = " going faster "
}
val mock = spyk< Car >(recordPrivateCalls = true )
every { mock[ " accelerate " ]() } returns " going not so fast "
assertEquals( " going not so fast " , mock.drive())
verifySequence {
mock.drive()
mock[ " accelerate " ]()
} Wenn Sie private Anrufe überprüfen möchten, sollten Sie einen spyk mit recordPrivateCalls = true erstellen
Darüber hinaus ermöglicht eine ausführlichere Syntax, Eigenschaften zu erhalten und festzulegen, kombiniert mit denselben dynamischen Aufrufen:
val mock = spyk( Team (), recordPrivateCalls = true )
every { mock getProperty " speed " } returns 33
every { mock setProperty " acceleration " value less( 5 ) } just runs
justRun { mock invokeNoArgs " privateMethod " }
every { mock invoke " openDoor " withArguments listOf ( " left " , " rear " ) } returns " OK "
verify { mock getProperty " speed " }
verify { mock setProperty " acceleration " value less( 5 ) }
verify { mock invoke " openDoor " withArguments listOf ( " left " , " rear " ) } Sie können über fieldValue auf die Backing -Felder zugreifen und value für den festgelegten Wert verwenden.
HINWEIS: In den folgenden Beispielen verwenden wir propertyType , um den Typ des fieldValue anzugeben. Dies ist erforderlich, da es möglich ist, den Typ automatisch für den Getter zu erfassen. Verwenden Sie nullablePropertyType , um einen Nullable -Typ anzugeben.
val mock = spyk( MockCls (), recordPrivateCalls = true )
every { mock.property } answers { fieldValue + 6 }
every { mock.property = any() } propertyType Int :: class answers { fieldValue + = value }
every { mock getProperty " property " } propertyType Int :: class answers { fieldValue + 6 }
every { mock setProperty " property " value any< Int >() } propertyType Int :: class answers { fieldValue + = value }
every {
mock.property = any()
} propertyType Int :: class answers {
fieldValue = value + 1
} andThen {
fieldValue = value - 1
}Hinzufügen von zusätzlichen Verhaltensweisen über Schnittstellen und Stubieren:
val spy = spyk( System . out , moreInterfaces = arrayOf( Runnable :: class ))
spy. println ( 555 )
every {
(spy as Runnable ). run ()
} answers {
(self as PrintStream ). println ( " Run! Run! Run! " )
}
val thread = Thread (spy as Runnable )
thread.start()
thread.join() Nichts Besonderes hier. Wenn Sie eine Funktion haben, die Nothing zurückgibt:
fun quit ( status : Int ): Nothing {
exitProcess(status)
}Dann können Sie zum Beispiel eine Ausnahme als Verhalten machen:
every { quit( 1 ) } throws Exception ( " this is a test " ) Ein Scoped -Mock ist ein Schein, das sich automatisch selbst entkockelt, nachdem der Codeblock als Parameter ausgeführt wurde. Sie können die Funktionen mockkObject , mockkStatic und mockkConstructor verwenden.
object ObjBeingMocked {
fun add ( a : Int , b : Int ) = a + b
}
// ObjBeingMocked will be unmocked after this scope
mockkObject( ObjBeingMocked ) {
assertEquals( 3 , ObjBeingMocked .add( 1 , 2 ))
every { ObjBeingMocked .add( 1 , 2 ) } returns 55
assertEquals( 55 , ObjBeingMocked .add( 1 , 2 ))
} Eine sehr einfache Möglichkeit, neue Matcher zu erstellen, besteht darin, eine Funktion an MockKMatcherScope oder MockKVerificationScope anzuhängen und die match zu verwenden:
fun MockKMatcherScope. seqEq ( seq : Sequence < String >) = match< Sequence < String >> {
it.toList() == seq.toList()
} Es ist auch möglich, fortgeschrittenere Matcher durch die Implementierung der Matcher -Schnittstelle zu erstellen.
Beispiel für einen benutzerdefinierten Match, der die Liste ohne Bestellung vergleicht:
@Test
fun test () {
class MockCls {
fun op ( a : List < Int >) = a.reversed()
}
val mock = mockk< MockCls >()
every { mock.op(any()) } returns listOf ( 5 , 6 , 9 )
println (mock.op( listOf ( 1 , 2 , 3 )))
verify { mock.op(matchListWithoutOrder( 3 , 2 , 1 )) }
}
data class ListWithoutOrderMatcher < T >(
val expectedList : List < T >,
val refEq : Boolean
) : Matcher<List<T>> {
val map = buildCountsMap(expectedList, refEq)
override fun match ( arg : List < T > ? ): Boolean {
if (arg == null ) return false
return buildCountsMap(arg, refEq) == map
}
private fun buildCountsMap ( list : List < T >, ref : Boolean ): Map < Any ?, Int > {
val map = mutableMapOf< Any ?, Int >()
for (item in list) {
val key = when {
item == null -> nullKey
refEq -> InternalPlatform .ref(item)
else -> item
}
map.compute(key, { _, value -> (value ? : 0 ) + 1 })
}
return map
}
override fun toString () = " matchListWithoutOrder( $expectedList ) "
@Suppress( " UNCHECKED_CAST " )
override fun substitute ( map : Map < Any , Any >): Matcher < List < T >> {
return copy(expectedList = expectedList.map { map.getOrDefault(it as Any? , it) } as List < T >)
}
companion object {
val nullKey = Any ()
}
}
inline fun < reified T : List < E >, E : Any > MockKMatcherScope. matchListWithoutOrder (
vararg items : E ,
refEq : Boolean = true
): T = match( ListWithoutOrderMatcher ( listOf ( * items), refEq))Beispiel Verwenden der Reflexion, um alle Methoden auf einem Immobilienobjekt zu verspotten
val builderFunctions = MyBuilder :: class .memberFunctions.filter { it.returnType.classifier == MyBuilder :: class }
val builderMock = mockk< MyBuilder > {
builderFunctions.forEach { func ->
every {
val params = listOf< Any ?>(builderMock) + func.parameters.drop( 1 ).map { any(it.type.classifier as KClass < Any >) }
func.call( * params.toTypedArray())
} answers {
this @mockk
}
}
}Um die Parameter global anzupassen, können Sie einige Einstellungen in einer Ressourcendatei angeben.
Wie man verwendet:
io/mockk/settings.properties -Datei in src/main/resources . relaxed =true|false
relaxUnitFun =true|false
recordPrivateCalls =true|false
stackTracesOnVerify =true|false
stackTracesAlignment =left|center stackTracesAlignment bestimmt, ob die Stapelspuren an der Zentrum (Standard) oder links ausgerichtet werden sollen (was mehr mit den üblichen JVM -Stacktraces übereinstimmt).
Hier sind ein paar Tische, mit denen Sie die DSL beherrschen können.
| Funktion | Beschreibung |
|---|---|
mockk<T>(...) | baut einen normalen Mock |
spyk<T>() | Erstellt einen Spion mit dem Standardkonstruktor |
spyk(obj) | baut einen Spion, indem er aus obj kopiert |
slot | schafft einen erfassenden Slot |
every | Startet einen Stummelblock |
coEvery | Startet einen Stummelblock für Coroutinen |
verify | Startet einen Verifizierungsblock |
coVerify | Startet einen Bestätigungsblock für Coroutinen |
verifyAll | Startet einen Verifizierungsblock, der alle Anrufe enthalten sollte |
coVerifyAll | Startet einen Verifizierungsblock, der alle Aufrufe nach Coroutinen enthalten sollte |
verifyOrder | Startet einen Verifizierungsblock, der die Reihenfolge überprüft |
coVerifyOrder | Startet einen Verifizierungsblock, der die Bestellung auf Coroutinen überprüft |
verifySequence | Startet einen Verifizierungsblock, der überprüft, ob alle Anrufe in einer bestimmten Sequenz getätigt wurden |
coVerifySequence | Startet einen Verifizierungsblock, der überprüft, ob alle Anrufe in einer bestimmten Sequenz für Coroutinen getätigt wurden |
excludeRecords | schließen Sie einige Anrufe von der Aufzeichnung aus |
confirmVerified | bestätigt, dass alle aufgezeichneten Anrufe verifiziert wurden |
checkUnnecessaryStub | bestätigt, dass alle aufgezeichneten Anrufe mindestens einmal verwendet werden |
clearMocks | Löscht die angegebenen Mocks |
registerInstanceFactory | Ermöglicht es Ihnen, die Art der Instanziierung für ein bestimmtes Objekt neu zu definieren |
mockkClass | Erstellt ein reguläres Schein, indem er die Klasse als Parameter überholt |
mockkObject | verwandelt ein Objekt in ein Objektspott oder löscht es, wenn bereits transformiert wurde |
unmockkObject | verwandelt ein Objekt verspottet wieder in ein reguläres Objekt |
mockkStatic | macht ein statisches Mock aus einer Klasse heraus oder räumt es frei, wenn es bereits transformiert wurde |
unmockkStatic | verwandelt ein statisches Mock wieder in eine reguläre Klasse |
clearStaticMockk | löscht ein statisches Verspottung |
mockkConstructor | lässt einen Konstruktor aus einer Klasse verspotten oder löscht ihn, wenn er bereits transformiert wurde |
unmockkConstructor | verwandelt einen Konstruktorspott in eine reguläre Klasse zurück |
clearConstructorMockk | löscht den Konstruktor -Schein |
unmockkAll | Unmocks -Objekt-, statische und Konstruktorspottungen |
clearAllMocks | löscht reguläre, Objekt-, statische und Konstruktor -Mocke |
Standardmäßig werden einfache Argumente mit eq() übereinstimmen
| Match | Beschreibung |
|---|---|
any() | entspricht jedem Argument |
any(Class) | entspricht jedem Argument der Give -Klasse (für reflektierendes Verspotten) |
allAny() | Spezielle Matcher, die any() anstelle von eq() für Matcher verwendet, die als einfache Argumente bereitgestellt werden |
isNull() | Überprüft, ob der Wert null ist |
isNull(inverse=true) | Überprüft, ob der Wert nicht null ist |
ofType(type) | Überprüft, ob der Wert zum Typ gehört |
match { it.startsWith("string") } | Übereinstimmung über das bestandene Prädikat |
coMatch { it.startsWith("string") } | Übereinstimmung über das bestandene Coroutine -Prädikat |
matchNullable { it?.startsWith("string") } | entspricht dem Nullierwert über das bestandene Prädikat |
coMatchNullable { it?.startsWith("string") } | entspricht dem Nullierwert über das bestandene Coroutine -Prädikat |
eq(value) | Übereinstimmt, wenn der Wert dem bereitgestellten Wert über die deepEquals -Funktion entspricht |
eq(value, inverse=true) | Übereinstimmt, wenn der Wert nicht dem angegebenen Wert über die deepEquals -Funktion entspricht |
neq(value) | Übereinstimmt, wenn der Wert nicht dem angegebenen Wert über die deepEquals -Funktion entspricht |
refEq(value) | Übereinstimmung, wenn der Wert dem angegebenen Wert durch Referenzvergleich entspricht |
refEq(value, inverse=true) | Übereinstimmung, wenn der Wert nicht dem angegebenen Wert durch Referenzvergleich entspricht |
nrefEq(value) | Übereinstimmung, wenn der Wert nicht dem angegebenen Wert durch Referenzvergleich entspricht |
cmpEq(value) | Übereinstimmt, wenn der Wert dem bereitgestellten Wert über die compareTo entspricht |
less(value) | Übereinstimmt, wenn der Wert unter dem bereitgestellten Wert über die compareTo ist |
more(value) | Übereinstimmt, wenn der Wert mehr als der bereitgestellte Wert über die compareTo ist |
less(value, andEquals=true) | Übereinstimmt, wenn der Wert kleiner oder gleich dem bereitgestellten Wert über die compareTo ist |
more(value, andEquals=true) | Übereinstimmt, wenn der Wert mehr als oder gleich dem bereitgestellten Wert über die compareTo ist |
range(from, to, fromInclusive=true, toInclusive=true) | Übereinstimmt, wenn sich der Wert über die compareTo im Bereich befindet |
and(left, right) | kombiniert zwei Matcher über eine logische und |
or(left, right) | kombiniert zwei Matcher über eine logische oder |
not(matcher) | negiert den Matcher |
capture(slot) | erfasst einen nicht nullbaren Wert für einen CapturingSlot |
captureNullable(slot) | erfasst einen nullbaren Wert für einen CapturingSlot |
capture(mutableList) | erfasst einen Wert für eine Liste |
captureNullable(mutableList) | erfasst einen Wert für eine Liste zusammen mit Nullwerten |
captureLambda() | fängt eine Lambda ein |
captureCoroutine() | erfasst eine Coroutine |
invoke(...) | Ruft ein übereinstimmendes Argument an |
coInvoke(...) | Ruft ein übereinstimmendes Argument für eine Coroutine an |
hint(cls) | Hinweise auf den nächsten Rückgabetyp, falls er gelöscht wird |
anyVararg() | entspricht allen Elementen in einem Vararg |
varargAny(matcher) | Übereinstimmungen, wenn ein Element mit dem Match übereinstimmt |
varargAll(matcher) | Übereinstimmungen, wenn alle Elemente mit dem Match übereinstimmen |
any...Vararg() | Übereinstimmung mit allen Elementen in Vararg (spezifisch für primitive Typen) |
varargAny...(matcher) | Übereinstimmungen, wenn ein Element mit dem Matcher übereinstimmt (spezifisch für den primitiven Typ) |
varargAll...(matcher) | Übereinstimmungen, wenn alle Elemente mit dem Matcher übereinstimmen (spezifisch für den primitiven Typ) |
Nur ein paar spezielle Matcher, die nur im Verifizierungsmodus verfügbar sind:
| Match | Beschreibung |
|---|---|
withArg { code } | entspricht jedem Wert und ermöglicht es, einen Code auszuführen |
withNullableArg { code } | entspricht jedem nullbaren Wert und ermöglicht es, einen Code auszuführen |
coWithArg { code } | entspricht jedem Wert und ermöglicht es, einen Coroutine -Code auszuführen |
coWithNullableArg { code } | entspricht jedem nullbaren Wert und ermöglicht es, einen Coroutine -Code auszuführen |
| Validator | Beschreibung |
|---|---|
verify { mock.call() } | Überprüfen Sie eine ungeordnete Überprüfung, dass ein Anruf ausgeführt wurde |
verify(inverse=true) { mock.call() } | Überprüfung durchführen, dass ein Anruf nicht ausgeführt wurde |
verify(atLeast=n) { mock.call() } | Überprüfung durchführen, dass ein Anruf mindestens n -mal durchgeführt wurde |
verify(atMost=n) { mock.call() } | Überprüfen Sie die nicht n |
verify(exactly=n) { mock.call() } | Überprüfung durchführen, dass ein Anruf genau n -mal durchgeführt wurde |
verifyAll { mock.call1(); mock.call2() } | Überprüfung durchführen, dass nur die angegebenen Anrufe für die genannten Mocks ausgeführt wurden |
verifyOrder { mock.call1(); mock.call2() } | Überprüfen Sie, ob die Abfolge der Anrufe nacheinander ging |
verifySequence { mock.call1(); mock.call2() } | Überprüfen |
verify { mock wasNot Called } | Verifizieren Sie, dass ein Schein nicht gerufen wurde |
verify { listOf(mock1, mock2) wasNot Called } | Überprüfen Sie, ob eine Liste von Mocks nicht gerufen wurde |
Eine Antwort kann von einer oder mehreren zusätzlichen Antworten verfolgt werden.
| Antwort | Beschreibung |
|---|---|
returns value | Geben Sie an, dass der übereinstimmende Anruf einen bestimmten Wert zurückgibt |
returnsMany list | Geben Sie an, dass der übereinstimmende Anruf einen Wert aus der Liste zurückgibt, wobei nachfolgende Anrufe das nächste Element zurückgeben |
returnsArgument(n) | Geben Sie an, dass der übereinstimmende Anruf das n -te Argument dieses Anrufs zurückgibt |
throws ex | Geben Sie an, dass der übereinstimmende Anruf eine Ausnahme ausgelöst hat |
throwsMany list | Geben Sie an, dass der übereinstimmende Anruf eine Ausnahme aus der Liste bringt, wobei nachfolgende Anrufe die nächste Ausnahme auswerfen |
answers { code } | Geben Sie an, dass die übereinstimmenden Anrufantworten mit einem Codeblock mit answer scope vorgenommen wurden |
coAnswers { code } | Geben Sie an, dass die übereinstimmenden Anrufantworten mit einem Coroutine -Code -Block mit answer scope |
answers answerObj | Geben Sie an, dass die übereinstimmenden Anrufantworten mit einem Antwortobjekt Antworten |
answers { nothing } | Geben Sie an, dass der übereinstimmende Anruf Antworten null |
just Runs | Geben Sie an, dass der übereinstimmende Anruf zurückgekehrt ist (Rückgabe null) |
just Awaits | Geben Sie an, dass der übereinstimmende Anruf nie zurückgibt (seit V1.13.3 verfügbar) |
propertyType Class | Geben Sie den Typ des Backing -Feld -Accessors an |
nullablePropertyType Class | Geben Sie den Typ des Backing -Feld -Accessors als nullierbarer Typ an |
Bei jedem konsequenten Anruf wird eine nächste Antwort zurückgegeben und der letzte Wert bleibt bestehen. Dies ähnelt also der returnsMany .
| Zusätzliche Antwort | Beschreibung |
|---|---|
andThen value | Geben Sie an, dass der übereinstimmende Anruf einen angegebenen Wert zurückgibt |
andThenMany list | Geben Sie an, dass der übereinstimmende Anruf einen Wert aus der Liste zurückgibt, wobei nachfolgende Anrufe das nächste Element zurückgeben |
andThenThrows ex | Geben Sie an, dass der übereinstimmende Anruf eine Ausnahme ausgelöst hat |
andThenThrowsMany ex | Geben Sie an, dass der übereinstimmende Anruf eine Ausnahme aus der Liste bringt, wobei nachfolgende Anrufe die nächste Ausnahme auswerfen |
andThen { code } | Geben Sie an, dass die übereinstimmenden Anrufantworten mit einem Codeblock mit answer scope vorgenommen wurden |
coAndThen { code } | Geben Sie an, dass die übereinstimmenden Anrufantworten mit einem Coroutine -Code -Block mit answer scope |
andThenAnswer answerObj | Geben Sie an, dass die übereinstimmenden Anrufantworten mit einem Antwortobjekt Antworten |
andThen { nothing } | Geben Sie an, dass der übereinstimmende Anruf Antworten null |
andThenJust Runs | Geben Sie an, dass der übereinstimmende Anruf zurückgegeben wird (seit V1.12.2 verfügbar). |
andThenJust Awaits | Geben Sie an, dass der übereinstimmende Anruf nie zurückkehrt (seit V1.13.3 verfügbar). |
| Parameter | Beschreibung |
|---|---|
call | ein Anrufobjekt, das aus einem Aufruf und einem Matcher besteht |
invocation | Enthält Informationen zur tatsächlichen Funktion, die aufgerufen wurde |
matcher | Enthält Informationen zu dem Match, der zum Aufruf entspricht |
self | Verweis auf die Objektaufruf erstellt |
method | Verweis auf die Funktionsaufruf erstellt |
args | Verweis auf die Aufrufargumente |
nArgs | Anzahl der Argumente für Aufrufe |
arg(n) | N -ter Argument |
firstArg() | Erstes Argument |
secondArg() | Zweites Argument |
thirdArg() | Dritter Argument |
lastArg() | Letzter Argument |
captured() | Das letzte Element in der Liste zur Bequemlichkeit bei der Erfassung einer Liste |
lambda<...>().invoke() | Rufen Sie die erfasste Lambda an |
coroutine<...>().coInvoke() | Rufen Sie die erfasste Coroutine an |
nothing | NULL -Wert für die Rückgabe nothing als Antwort |
fieldValue | Accessor auf dem Bereich der Eigenschaftssicherung |
fieldValueAny | Accessor to the Property Backing -Feld mit Any? Typ |
value | Wert wird festgelegt, auf den gleichen Typ wie das Feld der Eigenschaftssicherung gegossen |
valueAny | Wert, der eingestellt wird, mit Any? Typ |
callOriginal | Ruft die ursprüngliche Funktion auf |
| Parameter | Beschreibung |
|---|---|
position | die Position eines Arguments in einem Vararg -Array |
nArgs | Gesamtzahl von Argumenten in einem Vararg -Array |
Sie können dieses Projekt auch unterstützen, indem Sie Sponsor werden. Ihr Logo wird hier mit einem Link zu Ihrer Website angezeigt.
Vielen Dank an alle unsere Unterstützer!
Dieses Projekt besteht dank aller Menschen, die einen Beitrag leisten.
Um Fragen zu stellen, verwenden Sie bitte den Stapelüberlauf oder ein Gitter.
Um Fehler zu melden, verwenden Sie bitte das GitHub -Projekt.