Yang perlu Anda mulai hanyalah menambahkan ketergantungan ke perpustakaan MockK .
| Mendekati | Petunjuk |
|---|---|
![]() | TestimPlementation "io.mockk: mockk: $ {mockkversion}"
|
(Kotlin DSL) | TestimPlementation ("io.mockk: mockk: $ {mockkversion}") |
![]() | <mendeken>
<groupId> io.mockk </groupid>
<Artifactid> mockk-jvm </stifactid>
<version> $ {mockkversion} </version>
<scope> tes </seupop>
</dependency>
|
TestimPlementation "io.mockk: mockk-android: $ {mockkversion}"
TestimPlementation "io.mockk: mockk-agent: $ {mockkversion}"
| |
AndroidTesTImplementation "io.mockk: mockk-android: $ {mockkversion}"
AndroidTesTimplementation "io.mockk: mockk-agent: $ {mockkversion}"
|
Contoh paling sederhana. Secara default ejekan sangat ketat, jadi Anda perlu memberikan beberapa perilaku.
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)Lihat bagian "Fitur" di bawah ini untuk contoh yang lebih rinci.
Dari versi 1.13.0 mockk mendukung Kotlin 1.4 dan lebih tinggi
mockkStatic tidak dapat bekerja pada JDK 16+; InaccessibleObjectException / IllegalAccessException : Baca lebih lanjut di siniDaftar isi:
Periksa serangkaian artikel "mengejek bukanlah ilmu roket" di KT. Academy yang menggambarkan mockk dari dasar -dasar mengejek hingga deskripsi semua fitur canggih.
Dasar -dasar
Verifikasi perilaku dan perilaku yang diharapkan
Fitur Mockk
Fitur Mockk Advanced
Menguji quarkus dengan Kotlin, Junit dan Mockk
Mengungkap Sihir Hitam Mockk (EN, Terjemahan)
Buku Panduan Mockk
“Kotlin Unit Testing with Mockk” oleh Marco Cattaneo
(Video) Gunakan verifikasi di mockk untuk memvalidasi panggilan fungsi pada objek yang diejek
Pengujian dengan kursus berbayar Mockk di raywenderlich.com
TDD untuk tutorial video android Bagian 1, Bagian 2 oleh Ryan Kay
(Video) Pengembang Android Live Coding #13: Unit Testing dengan Mockk, Coroutines, Test Driven Development
Kotlinconf 2018 - Praktik Terbaik untuk Pengujian Unit di Kotlin oleh Philipp Hauer
Kotlin-fullstack-sample menggunakan proyek mockk yang ditutupi dengan tes
Artikel Dzone
Artikel Habrahabr (RU)
Mengejek di Kotlin dengan Mockk - Yannick de Turck
Anda dapat menggunakan anotasi untuk menyederhanakan pembuatan objek tiruan:
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
}
} Injeksi pertama kali mencoba mencocokkan properti dengan nama, kemudian dengan kelas atau superclass. Periksa parameter lookupType untuk kustomisasi.
Properti disuntikkan bahkan jika private diterapkan. Konstruktor untuk injeksi dipilih dari jumlah argumen terbesar ke terendah.
@InjectMockKs secara default hanya menyuntikkan lateinit var s atau var s yang tidak ditetapkan. Untuk mengubah ini, gunakan overrideValues = true . Ini akan menetapkan nilai bahkan jika sudah diinisialisasi entah bagaimana. Untuk menyuntikkan val s, gunakan injectImmutable = true . Untuk notasi yang lebih pendek gunakan @OverrideMockKs yang melakukan hal yang sama dengan @InjectMockKs secara default, tetapi menyalakan kedua bendera ini.
Junit 4 mengekspos API berbasis aturan untuk memungkinkan beberapa otomatisasi setelah siklus hidup uji. Mockk termasuk aturan yang menggunakan ini untuk mengatur dan merobohkan tiruan Anda tanpa perlu secara manual memanggil MockKAnnotations.init(this) . Contoh:
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
}
} Di Junit5 Anda dapat menggunakan MockKExtension untuk menginisialisasi tiruan Anda.
@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
}
} Selain itu, ini menambahkan kemungkinan untuk menggunakan @MockK dan @RelaxedMockK pada parameter fungsi uji:
@Test
fun calculateAddsValues1 (@MockK car1 : Car , @RelaxedMockK car2 : Car ) {
// ... use car1 and car2
} Akhirnya, ekstensi ini akan menghubungi unmockkAll dan clearAllMocks dalam panggilan balik @AfterAll , memastikan lingkungan pengujian Anda bersih setelah setiap eksekusi kelas tes. Anda dapat menonaktifkan perilaku ini dengan menambahkan anotasi @MockKExtension.KeepMocks ke kelas Anda atau secara global dengan mengatur mockk.junit.extension.keepmocks=true . (Karena v1.13.11) sebagai alternatif, karena clearAllMocks secara default ( currentThreadOnly=false ) tidak aman-utas, jika Anda perlu menjalankan tes secara paralel, Anda dapat menambahkan MockKExtension.RequireParallelTesting anotasi ke kelas @AfterAll ke dalam mockk.junit.extension.requireParallelTesting=true . Jika clearAllMocks dipanggil secara eksplisit, Anda dapat menyediakan clearAllMocks(currentThreadOnly = true) sehingga hanya membersihkan tiruan yang dibuat dalam utas yang sama (karena v1.13.12).
Anda dapat memastikan bahwa semua metode yang ternak sebenarnya diverifikasi dengan juga anotasi kelas tes Anda dengan @MockKExtension.ConfirmVerification .
Ini akan secara internal menelepon confirmVerified pada semua tiruan setelah setiap tes, untuk memastikan tidak ada kerasukan yang tidak perlu.
Harap dicatat bahwa perilaku ini mungkin tidak berfungsi seperti yang diharapkan saat menjalankan tes di IDE Anda, karena lulusan yang menangani penanganan pengecualian yang dilemparkan ketika panggilan confirmVerified ini gagal.
Anda dapat memastikan bahwa semua metode yang ternak berguna - digunakan setidaknya satu kali - dengan juga menganotasi kelas tes Anda dengan @MockKExtension.CheckUnnecessaryStub .
Ini secara internal akan menghubungi checkUnnecessaryStub pada semua tiruan setelah setiap tes, untuk memastikan tidak ada kerasukan yang tidak perlu.
Mata -mata memungkinkan Anda untuk mencampur mocks dan objek nyata.
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)Catatan 1: Objek mata -mata adalah salinan objek yang ditularkan. Catatan 2: Ada masalah yang diketahui jika menggunakan mata -mata dengan fungsi penangguhan: #554
relaxed mock adalah tiruan yang mengembalikan nilai sederhana untuk semua fungsi. Ini memungkinkan Anda untuk melewatkan perilaku menentukan untuk setiap kasus, sambil tetap mematikan hal -hal yang Anda butuhkan. Untuk jenis referensi, tiruan dirantai dikembalikan.
val car = mockk< Car >(relaxed = true )
car.drive( Direction . NORTH ) // returns null
verify { car.drive( Direction . NORTH ) }
confirmVerified(car)Catatan: Mocking santai bekerja buruk dengan jenis pengembalian umum. Pengecualian gips kelas biasanya dilemparkan dalam kasus ini. Pilihlah untuk mematikan secara manual dalam hal jenis pengembalian generik.
Solusi:
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() Kadang -kadang, Anda perlu mematikan beberapa fungsi, tetapi masih memanggil metode nyata pada orang lain, atau pada argumen tertentu. Ini dimungkinkan dengan meneruskan callOriginal() ke answers , yang berfungsi untuk ejek santai dan tidak disesuaikan.
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 Jika Anda ingin fungsi Unit -returning menjadi rileks, Anda dapat menggunakan relaxUnitFun = true sebagai argumen untuk fungsi mockk , @MockK annotation atau MockKAnnotations.init function.
Fungsi:
mockk< ClassBeingMocked >(relaxUnitFun = true )Anotasi:
@MockK(relaxUnitFun = true )
lateinit var mock1 : ClassBeingMocked
init {
MockKAnnotations . init ( this )
}Mockkannotations.init:
@MockK
lateinit var mock2 : ClassBeingMocked
init {
MockKAnnotations . init ( this , relaxUnitFun = true )
}Objek dapat diubah menjadi tiruan dengan cara berikut:
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 )) Untuk kembali, gunakan unmockkObject atau unmockkAll (lebih destruktif: membatalkan objek, tiruan statis dan konstruktor)
@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()
}Terlepas dari pembatasan bahasa Kotlin, Anda dapat membuat contoh objek baru jika diperlukan dengan menguji logika:
val newObjectMock = mockk< ObjBeingMocked >() Terkadang Anda membutuhkan tiruan kelas sewenang -wenang. Gunakan mockkClass dalam kasus tersebut.
val car = mockkClass( Car :: class )
every { car.drive( Direction . NORTH ) } returns Outcome . OK
car.drive( Direction . NORTH ) // returns OK
verify { car.drive( Direction . NORTH ) } Enum dapat diejek menggunakan mockkObject :
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)Terkadang, terutama dalam kode yang tidak Anda miliki, Anda perlu mengejek objek yang baru dibuat. Untuk tujuan ini, konstruksi berikut disediakan:
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 ) } Gagasan dasarnya adalah bahwa tepat setelah konstruktor kelas yang diejek dieksekusi (salah satu dari mereka), objek menjadi constructed mock .
Perilaku mengejek dari tiruan seperti itu terhubung ke prototype mock khusus yang dilambangkan dengan anyConstructed<MockCls>() .
Ada satu contoh per kelas prototype mock seperti itu. Perekaman panggilan juga terjadi pada prototype mock .
Jika tidak ada perilaku untuk fungsi yang ditentukan, maka fungsi asli dieksekusi.
Jika kelas memiliki lebih dari satu konstruktor, masing -masing dapat diejek secara terpisah:
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 )
} Perhatikan bahwa dalam hal ini, prototype mock dibuat untuk setiap set pencocokan argumen yang diteruskan ke constructedWith .
Anda dapat mencampur argumen dan pencocokan reguler:
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)Anda bisa menanggul rantai panggilan:
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) CATATAN: Jika jenis pengembalian fungsi adalah generik maka informasi tentang tipe aktual hilang.
Untuk membuat panggilan rantai berfungsi, diperlukan informasi tambahan.
Sebagian besar waktu kerangka kerja akan menangkap pengecualian dan melakukan autohinting .
Dalam hal ini secara eksplisit diperlukan, gunakan hint sebelum melakukan panggilan berikutnya.
every { obj.op2( 1 , 2 ).hint( Int :: class ).op1( 3 , 4 ) } returns 5Dari versi 1.9.1 tiruan dapat dirantai menjadi hierarki:
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 "
}
}
)
} Anda dapat menangkap argumen ke CapturingSlot atau MutableList .
CapturingSlot biasanya dibuat melalui slot<T : Any?>() Dan mungkin untuk menangkap tipe yang tidak dapat dibatalkan dan tidak dapat dibatalkan. MutableList dimaksudkan untuk menangkap banyak nilai selama pengujian.
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) Anda dapat memeriksa jumlah panggilan dengan parameter atLeast , atMost atau exactly :
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) Atau Anda dapat menggunakan verifyCount :
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 memverifikasi bahwa semua panggilan terjadi tanpa memeriksa pesanan mereka.verifySequence memverifikasi bahwa panggilan terjadi dalam urutan yang ditentukan.verifyOrder memverifikasi bahwa panggilan terjadi dalam urutan tertentu.wasNot Called memverifikasi bahwa tiruan (atau daftar tiruan) tidak dipanggil sama sekali. 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) Untuk memeriksa ulang bahwa semua panggilan diverifikasi dengan verify... konstruksi, Anda dapat menggunakan confirmVerified :
confirmVerified(mock1, mock2) Tidak masuk akal untuk menggunakannya untuk verifySequence dan verifyAll , karena metode verifikasi ini sudah secara mendalam mencakup semua panggilan dengan verifikasi.
Ini akan melempar pengecualian jika ada beberapa panggilan yang tersisa tanpa verifikasi.
Beberapa panggilan dapat dikecualikan dari konfirmasi ini, periksa bagian selanjutnya untuk lebih jelasnya.
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 verificationKarena kode uji yang bersih & dapat dipelihara membutuhkan kode nol yang tidak perlu, Anda dapat memastikan bahwa tidak ada stub yang tidak perlu.
checkUnnecessaryStub(mock1, mock2)Ini akan melempar pengecualian jika ada beberapa panggilan yang dinyatakan pada mocks yang tidak digunakan oleh kode yang diuji. Ini dapat terjadi jika Anda telah menyatakan beberapa stub yang benar -benar tidak perlu atau jika kode yang diuji tidak memanggil yang diharapkan.
Untuk mengecualikan panggilan yang tidak penting agar tidak direkam, Anda dapat menggunakan excludeRecords :
excludeRecords { mock.operation(any(), 5 ) } Semua panggilan yang cocok akan dikecualikan dari perekaman. Ini mungkin berguna jika Anda menggunakan verifikasi lengkap: verifyAll , verifySequence atau 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) Untuk memverifikasi operasi bersamaan, Anda dapat menggunakan timeout = xxx :
mockk< MockCls > {
every { sum( 1 , 2 ) } returns 4
Thread {
Thread .sleep( 2000 )
sum( 1 , 2 )
}.start()
verify(timeout = 3000 ) { sum( 1 , 2 ) }
}Ini akan menunggu sampai salah satu dari dua negara bagian berikut: salah satu verifikasi dilewati atau batas waktu tercapai.
Jika suatu fungsi mengembalikan Unit , Anda dapat menggunakan konstruk justRun :
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 )
} Cara lain untuk menulis justRun { obj.sum(any(), 3) } :
every { obj.sum(any(), 3) } just Runsevery { obj.sum(any(), 3) } returns Unitevery { obj.sum(any(), 3) } answers { Unit }Untuk mengejek coroutine, Anda perlu menambahkan ketergantungan lain ke pustaka dukungan.
| Lulusan |
|---|
Testimeplementasi "org.jetbrains.kotlinx: Kotlinx-coroutines-core: xx" |
| Maven |
|---|
<mendeken>
<groupId> org.jetbrains.kotlinx </groupid>
<ArTifactid> Kotlinx-Coroutines-core </artifactid>
<version> xx </version>
<scope> tes </seupop>
</dependency> |
Kemudian Anda dapat menggunakan coEvery , coVerify , coMatch , coAssert , coRun , coAnswers atau coInvoke to Mock Mock Suspend Functions.
val car = mockk< Car >()
coEvery { car.drive( Direction . NORTH ) } returns Outcome . OK
car.drive( Direction . NORTH ) // returns OK
coVerify { car.drive( Direction . NORTH ) } Dan untuk mensimulasikan fungsi suspend yang tidak pernah kembali, Anda dapat menggunakan coJustAwait :
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
}Catatan: Ada masalah yang diketahui jika menggunakan mata -mata dengan fungsi penangguhan: #554
Kotlin memungkinkan Anda mendeklarasikan fungsi yang bukan milik kelas atau objek apa pun, yang disebut fungsi tingkat atas. Panggilan ini diterjemahkan ke metode statis di lingkungan jvm , dan kelas Java khusus dihasilkan untuk menahan fungsi. Fungsi tingkat atas ini dapat diejek menggunakan mockkStatic . Anda hanya perlu mengimpor fungsi dan meneruskan referensi sebagai argumen:
import com.cars.buildCar
val testCar = Car ()
mockkStatic(::buildCar)
every { buildCar() } returns testCar
assertEquals(testCar, buildCar())
verify { buildCar() } Mengejek fungsi akan menghapus ejekan yang ada dari fungsi lain yang dideklarasikan dalam file yang sama, setara dengan memanggil clearStaticMockk pada kelas tertutup yang dihasilkan.
Ada tiga jenis fungsi ekstensi di Kotlin:
Untuk suatu objek atau kelas, Anda dapat mengejek fungsi ekstensi hanya dengan membuat mockk biasa:
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()
}
} Untuk mengejek fungsi ekstensi modul-modul, Anda perlu membangun mockkStatic(...) dengan nama kelas modul sebagai argumen. Misalnya "pkg.filekt" untuk modul File.kt dalam paket pkg .
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()
} Di lingkungan jvm Anda dapat mengganti nama kelas dengan referensi fungsi:
mockkStatic( Obj ::extensionFunc) Perhatikan bahwa ini akan mengejek seluruh kelas pkg.FileKt , dan bukan hanya extensionFunc .
Sintaks ini juga berlaku untuk properti ekstensi:
val Obj .squareValue get() = value * value
mockkStatic( Obj ::squareValue) Jika @JvmName digunakan, tentukan sebagai nama kelas.
KHTTP.KT:
@file:JvmName( " KHttp " )
package khttp
// ... KHttp code Kode Pengujian:
mockkStatic( " khttp.KHttp " ) Terkadang Anda perlu tahu sedikit lebih banyak untuk mengejek fungsi ekstensi. Misalnya File.endsWith() memiliki classname yang sama sekali tidak dapat diprediksi:
mockkStatic( " kotlin.io.FilesKt__UtilsKt " )
every { File ( " abc " ).endsWith(any< String >()) } returns true
println ( File ( " abc " ).endsWith( " abc " )) Ini adalah perilaku Kotlin standar yang mungkin tidak dapat diprediksi. Gunakan Tools -> Kotlin -> Show Kotlin Bytecode atau periksa file .class di JAR Archive untuk mendeteksi nama -nama tersebut.
Dari versi 1.9.1, penanganan vararg yang lebih diperpanjang dimungkinkan:
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 )) // 6Jika Anda perlu mengejek fungsi pribadi, Anda dapat melakukannya melalui panggilan dinamis.
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 " ]()
} Jika Anda ingin memverifikasi panggilan pribadi, Anda harus membuat spyk dengan recordPrivateCalls = true
Selain itu, sintaksis yang lebih verbose memungkinkan Anda untuk mendapatkan dan mengatur properti, dikombinasikan dengan panggilan dinamis yang sama:
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 " ) } Anda dapat mengakses bidang pendukung melalui fieldValue dan menggunakan value untuk nilai yang ditetapkan.
Catatan: Dalam contoh di bawah ini, kami menggunakan propertyType untuk menentukan jenis fieldValue . Ini diperlukan karena dimungkinkan untuk menangkap jenis secara otomatis untuk pengambil. Gunakan nullablePropertyType untuk menentukan tipe nullable.
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
}Menambahkan perilaku tambahan melalui antarmuka dan mematahkannya:
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() Tidak ada yang istimewa di sini. Jika Anda memiliki fungsi yang tidak mengembalikan Nothing :
fun quit ( status : Int ): Nothing {
exitProcess(status)
}Maka Anda dapat misalnya melempar pengecualian sebagai perilaku:
every { quit( 1 ) } throws Exception ( " this is a test " ) Mock yang dilingkup adalah tiruan yang secara otomatis membuka gumpal setelah blok kode dilewati sebagai parameter telah dieksekusi. Anda dapat menggunakan fungsi mockkObject , mockkStatic dan mockkConstructor .
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 ))
} Cara yang sangat sederhana untuk membuat pencocokan baru adalah dengan melampirkan fungsi ke MockKMatcherScope atau MockKVerificationScope dan menggunakan fungsi match :
fun MockKMatcherScope. seqEq ( seq : Sequence < String >) = match< Sequence < String >> {
it.toList() == seq.toList()
} Dimungkinkan juga untuk membuat pencocokan yang lebih canggih dengan mengimplementasikan antarmuka Matcher .
Contoh pencocokan khusus yang membandingkan daftar tanpa pesanan:
@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))Contoh Menggunakan Refleksi Untuk Mengejek Semua Metode Pada Objek Gaya Pembangun
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
}
}
}Untuk menyesuaikan parameter secara global, ada beberapa pengaturan yang dapat Anda tentukan dalam file sumber daya.
Bagaimana menggunakan:
io/mockk/settings.properties di src/main/resources . relaxed =true|false
relaxUnitFun =true|false
recordPrivateCalls =true|false
stackTracesOnVerify =true|false
stackTracesAlignment =left|center stackTracesAlignment menentukan apakah akan menyelaraskan jejak tumpukan ke tengah (default), atau ke kiri (lebih konsisten dengan stacktraces JVM biasa).
Berikut adalah beberapa meja untuk membantu Anda menguasai DSL.
| Fungsi | Keterangan |
|---|---|
mockk<T>(...) | Membangun tiruan biasa |
spyk<T>() | Membangun mata -mata menggunakan konstruktor default |
spyk(obj) | Membangun mata -mata dengan menyalin dari obj |
slot | menciptakan slot penangkapan |
every | Mulai blok yang menanggalkan |
coEvery | Mulai blok yang menanggalkan coroutines |
verify | memulai blok verifikasi |
coVerify | memulai blok verifikasi untuk coroutine |
verifyAll | Mulai blok verifikasi yang harus mencakup semua panggilan |
coVerifyAll | Mulai blok verifikasi yang harus mencakup semua panggilan untuk coroutine |
verifyOrder | memulai blok verifikasi yang memeriksa pesanan |
coVerifyOrder | Mulai blok verifikasi yang memeriksa pesanan untuk coroutine |
verifySequence | Mulai blok verifikasi yang memeriksa apakah semua panggilan dilakukan dalam urutan yang ditentukan |
coVerifySequence | Mulai blok verifikasi yang memeriksa apakah semua panggilan dilakukan dalam urutan yang ditentukan untuk coroutine |
excludeRecords | mengecualikan beberapa panggilan agar tidak direkam |
confirmVerified | menegaskan bahwa semua panggilan yang direkam diverifikasi |
checkUnnecessaryStub | mengkonfirmasi bahwa semua panggilan yang direkam digunakan setidaknya sekali |
clearMocks | Menghapus tiruan yang ditentukan |
registerInstanceFactory | memungkinkan Anda untuk mendefinisikan kembali cara instantiasi untuk objek tertentu |
mockkClass | Membangun tiruan biasa dengan meneruskan kelas sebagai parameter |
mockkObject | mengubah objek menjadi tiruan objek, atau membersihkannya jika sudah diubah |
unmockkObject | Mengubah mock objek kembali menjadi objek biasa |
mockkStatic | membuat tiruan statis dari kelas, atau membersihkannya jika sudah diubah |
unmockkStatic | mengubah tiruan statis menjadi kelas reguler |
clearStaticMockk | membersihkan tiruan statis |
mockkConstructor | membuat tiruan konstruktor dari suatu kelas, atau membersihkannya jika sudah diubah |
unmockkConstructor | mengubah tiruan konstruktor kembali menjadi kelas reguler |
clearConstructorMockk | membersihkan tiruan konstruktor |
unmockkAll | Buka Objek, Statis dan Konstruktor Mocks |
clearAllMocks | membersihkan tiruan reguler, objek, statis dan konstruktor |
Secara default, argumen sederhana dicocokkan menggunakan eq()
| Pencocokan | Keterangan |
|---|---|
any() | cocok dengan argumen apa pun |
any(Class) | cocok dengan argumen apa pun dari kelas memberi (untuk mengejek reflektif) |
allAny() | pencocokan khusus yang menggunakan any() bukannya eq() untuk pencocokan yang disediakan sebagai argumen sederhana |
isNull() | memeriksa apakah nilainya nol |
isNull(inverse=true) | memeriksa apakah nilainya tidak nol |
ofType(type) | memeriksa apakah nilainya milik jenis |
match { it.startsWith("string") } | cocok dengan predikat yang dilewati |
coMatch { it.startsWith("string") } | cocok dengan predikat coroutine yang dilewati |
matchNullable { it?.startsWith("string") } | cocok dengan nilai nullable melalui predikat yang ditularkan |
coMatchNullable { it?.startsWith("string") } | Pencocokan nilai yang dapat dibatalkan melalui predikat coroutine yang ditularkan |
eq(value) | cocok jika nilainya sama dengan nilai yang disediakan melalui fungsi deepEquals |
eq(value, inverse=true) | cocok jika nilainya tidak sama dengan nilai yang disediakan melalui fungsi deepEquals |
neq(value) | cocok jika nilainya tidak sama dengan nilai yang disediakan melalui fungsi deepEquals |
refEq(value) | cocok jika nilainya sama dengan nilai yang disediakan melalui perbandingan referensi |
refEq(value, inverse=true) | cocok jika nilainya tidak sama dengan nilai yang disediakan melalui perbandingan referensi |
nrefEq(value) | cocok jika nilainya tidak sama dengan nilai yang disediakan melalui perbandingan referensi |
cmpEq(value) | cocok jika nilainya sama dengan nilai yang disediakan melalui fungsi compareTo |
less(value) | cocok jika nilainya kurang dari nilai yang disediakan melalui fungsi compareTo |
more(value) | cocok jika nilainya lebih dari nilai yang disediakan melalui fungsi compareTo |
less(value, andEquals=true) | cocok jika nilainya kurang dari atau sama dengan nilai yang disediakan melalui fungsi compareTo |
more(value, andEquals=true) | cocok jika nilainya lebih dari atau sama dengan nilai yang disediakan melalui fungsi compareTo |
range(from, to, fromInclusive=true, toInclusive=true) | cocok jika nilainya dalam kisaran melalui fungsi compareTo |
and(left, right) | menggabungkan dua pencocokan melalui logis dan |
or(left, right) | menggabungkan dua pencocokan melalui logis atau |
not(matcher) | meniadakan pencocokan |
capture(slot) | menangkap nilai yang tidak dapat dibatalkan ke CapturingSlot |
captureNullable(slot) | Menangkap nilai yang dapat dibatalkan ke CapturingSlot |
capture(mutableList) | menangkap nilai ke daftar |
captureNullable(mutableList) | menangkap nilai ke daftar bersama dengan nilai nol |
captureLambda() | menangkap lambda |
captureCoroutine() | menangkap coroutine |
invoke(...) | memanggil argumen yang cocok |
coInvoke(...) | memanggil argumen yang cocok untuk coroutine |
hint(cls) | mengisyaratkan jenis pengembalian berikutnya jika dihapus |
anyVararg() | cocok dengan elemen apa pun di vararg |
varargAny(matcher) | cocok jika ada elemen yang cocok dengan pencocokan |
varargAll(matcher) | cocok jika semua elemen cocok dengan pencocokan |
any...Vararg() | cocok dengan elemen apa pun di vararg (khusus untuk tipe primitif) |
varargAny...(matcher) | cocok jika ada elemen yang cocok dengan pencocokan (khusus dengan tipe primitif) |
varargAll...(matcher) | cocok jika semua elemen cocok dengan pencocokan (khusus dengan tipe primitif) |
Beberapa pencocokan khusus hanya tersedia dalam mode verifikasi:
| Pencocokan | Keterangan |
|---|---|
withArg { code } | cocok dengan nilai apa pun dan memungkinkan untuk menjalankan beberapa kode |
withNullableArg { code } | cocok dengan nilai apa pun dan memungkinkan untuk menjalankan beberapa kode |
coWithArg { code } | cocok dengan nilai apa pun dan memungkinkan untuk menjalankan beberapa kode coroutine |
coWithNullableArg { code } | cocok dengan nilai apa pun yang tidak dapat dibatalkan dan memungkinkan untuk menjalankan beberapa kode coroutine |
| Validator | Keterangan |
|---|---|
verify { mock.call() } | Melakukan verifikasi yang tidak tertib bahwa panggilan dilakukan |
verify(inverse=true) { mock.call() } | Melakukan verifikasi yang tidak tertib bahwa panggilan tidak dilakukan |
verify(atLeast=n) { mock.call() } | Melakukan verifikasi yang tidak tertib bahwa panggilan dilakukan setidaknya n kali |
verify(atMost=n) { mock.call() } | Melakukan verifikasi yang tidak tertib bahwa panggilan dilakukan paling banyak n kali |
verify(exactly=n) { mock.call() } | Melakukan verifikasi yang tidak tertib bahwa panggilan dilakukan tepat n kali |
verifyAll { mock.call1(); mock.call2() } | Melakukan verifikasi yang tidak tertib bahwa hanya panggilan yang ditentukan yang dieksekusi untuk tiruan yang disebutkan |
verifyOrder { mock.call1(); mock.call2() } | Melakukan verifikasi bahwa urutan panggilan berjalan satu demi satu |
verifySequence { mock.call1(); mock.call2() } | Melakukan verifikasi bahwa hanya urutan panggilan yang ditentukan yang dieksekusi untuk tiruan yang disebutkan |
verify { mock wasNot Called } | Melakukan verifikasi bahwa tiruan tidak dipanggil |
verify { listOf(mock1, mock2) wasNot Called } | Melakukan verifikasi bahwa daftar ejek tidak dipanggil |
Jawaban dapat ditindaklanjuti dengan satu atau lebih jawaban tambahan.
| Menjawab | Keterangan |
|---|---|
returns value | Tentukan bahwa panggilan yang cocok mengembalikan nilai yang ditentukan |
returnsMany list | Tentukan bahwa panggilan yang cocok mengembalikan nilai dari daftar, dengan panggilan berikutnya mengembalikan elemen berikutnya |
returnsArgument(n) | Tentukan bahwa panggilan yang cocok mengembalikan argumen ke -n dari panggilan itu |
throws ex | Tentukan bahwa panggilan yang cocok melempar pengecualian |
throwsMany list | Tentukan bahwa panggilan yang cocok melempar pengecualian dari daftar, dengan panggilan berikutnya melempar pengecualian berikutnya |
answers { code } | Tentukan bahwa panggilan panggilan yang cocok dengan blok kode yang dilingkupi dengan answer scope |
coAnswers { code } | Tentukan bahwa panggilan panggilan yang cocok dengan blok kode Coroutine dengan answer scope |
answers answerObj | Tentukan bahwa panggilan yang cocok menjawab dengan objek jawaban |
answers { nothing } | Tentukan bahwa panggilan yang cocok menjawab nol |
just Runs | Tentukan bahwa panggilan yang cocok adalah unit pengembalian (returns null) |
just Awaits | Tentukan bahwa panggilan yang cocok tidak pernah kembali (tersedia sejak v1.13.3) |
propertyType Class | Tentukan jenis aksesor bidang dukungan |
nullablePropertyType Class | Tentukan jenis aksesor bidang dukungan sebagai tipe yang tidak bisa ditentang |
Jawaban berikutnya dikembalikan pada setiap panggilan konsekuensi dan nilai terakhir tetap ada. Jadi ini mirip dengan semantik returnsMany .
| Jawaban tambahan | Keterangan |
|---|---|
andThen value | Tentukan bahwa panggilan yang cocok mengembalikan satu nilai yang ditentukan |
andThenMany list | Tentukan bahwa panggilan yang cocok mengembalikan nilai dari daftar, dengan panggilan berikutnya mengembalikan elemen berikutnya |
andThenThrows ex | Tentukan bahwa panggilan yang cocok melempar pengecualian |
andThenThrowsMany ex | Tentukan bahwa panggilan yang cocok melempar pengecualian dari daftar, dengan panggilan berikutnya melempar pengecualian berikutnya |
andThen { code } | Tentukan bahwa panggilan panggilan yang cocok dengan blok kode yang dilingkupi dengan answer scope |
coAndThen { code } | Tentukan bahwa panggilan panggilan yang cocok dengan blok kode Coroutine dengan answer scope |
andThenAnswer answerObj | Tentukan bahwa panggilan yang cocok menjawab dengan objek jawaban |
andThen { nothing } | Tentukan bahwa panggilan yang cocok menjawab nol |
andThenJust Runs | Tentukan bahwa panggilan yang cocok adalah unit pengembalian (tersedia sejak v1.12.2) |
andThenJust Awaits | Tentukan bahwa panggilan yang cocok tidak pernah kembali (tersedia sejak v1.13.3) |
| Parameter | Keterangan |
|---|---|
call | objek panggilan yang terdiri dari doa dan pencocokan |
invocation | berisi informasi mengenai fungsi aktual yang dipanggil |
matcher | berisi informasi mengenai pencocokan yang digunakan untuk mencocokkan doa |
self | referensi ke doa objek yang dibuat |
method | referensi ke doa fungsi yang dibuat |
args | referensi ke argumen doa |
nArgs | Jumlah argumen doa |
arg(n) | Argumen ke -n |
firstArg() | argumen pertama |
secondArg() | argumen kedua |
thirdArg() | argumen ketiga |
lastArg() | argumen terakhir |
captured() | elemen terakhir dalam daftar untuk kenyamanan saat menangkap ke daftar |
lambda<...>().invoke() | hubungi lambda yang ditangkap |
coroutine<...>().coInvoke() | Hubungi coroutine yang ditangkap |
nothing | nilai nol untuk tidak mengembalikan nothing sebagai jawaban |
fieldValue | aksesor ke bidang dukungan properti |
fieldValueAny | Accessor ke bidang dukungan properti dengan Any? jenis |
value | nilai diatur, dilemparkan ke jenis yang sama dengan bidang dukungan properti |
valueAny | Nilai ditetapkan, dengan Any? jenis |
callOriginal | memanggil fungsi asli |
| Parameter | Keterangan |
|---|---|
position | Posisi argumen dalam array vararg |
nArgs | jumlah keseluruhan argumen dalam array vararg |
Anda juga dapat mendukung proyek ini dengan menjadi sponsor. Logo Anda akan muncul di sini dengan tautan ke situs web Anda.
Terima kasih untuk semua pendukung kami!
Proyek ini ada berkat semua orang yang berkontribusi.
Untuk mengajukan pertanyaan, silakan gunakan Stack Overflow atau Gitter.
Untuk melaporkan bug, silakan gunakan proyek GitHub.