Kotlin MockK 사용법 (공식 문서 번역)
시작하기
MockK는 테스트 코드를 작성하기 위한 코틀린 Mock 라이브러리이다. 이 문서는 공식 문서를 한국어로 번역한 것이다.
설치
시작하기 위하여 필요한 것은 MockK 라이브러리에 종속성을 추가하는 것이다.
접근 | 명령 |
---|---|
Gradle | testImplementation "io.mockk:mockk:{version}" |
Gradle (Kotlin DSL) | testImplementation("io.mockk:mockk:{version}") |
Maven | <dependency> <groupId>io.mockk</groupId> <artifactId>mockk</artifactId> <version>{version}</version> <scope>test</scope> </dependency> |
Unit | testImplementation "io.mockk:mockk:{version}" |
Instrumented | androidTestImplementation "io.mockk:mockk-android:{version}" |
Common multiplatform | testImplementation "io.mockk:mockk-common:{version}" |
{version}
은 다음 버전에 해당한다.
- Kotlin 1.3+ 및 Coroutines 1.0+ 버전
- Kotlin 1.2 호환 버전
DSL 예제
가장 간단한 예제이다. 기본적으로 모의 객체는 엄격하므로 몇 가지 동작을 제공해야 한다.
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)
어노테이션(Annotations)
어노테이션을 사용하여 모의 객체의 생성을 간소화할 수 있다.
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) // 모들 모형에 relaxUnitFun을 켜둔다.
@Test
fun calculateAddsValues1() {
// ... use car1, car2, car3 and car4
}
}
인젝션는 먼저 속성을 이름으로 조합하고 다음 클래스 또는 수퍼 클래스에 일치한다. 사용자에 대한 lookupType
매개 변수를 확인한다.
private
으로 적용되는 경우에도 속성이 주입된다. 주입 생성자는 인수의 최대에서 최소까지 선택된다.
기본적으로 @InjectMockKs
는 lateinit var
또는 할당되지 않은 var
만을 삽입한다. 이를 변경하려면 overrideValues = true
를 사용한다. 이것은 이미 어떤 방법으로 초기화되는 경우에도 값을 할당한다. val
를 주입하려면 injectImmutable = true
를 사용한다. 짧은 형식의 경우, 디폴트로로 @InjectMockKs
와 같은 동작을 하는 @OverrideMockKs
을 사용하지만, 이 2개의 플래그를 선택한다.
JUnit5
JUnit5은 MockKExtension
을 사용하여 모의를 초기화 할 수 있다.
@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
}
}
또한 테스트 함수의 매개 변수에 @MockK
및 @RelaxedMockK
을 사용할 수 있는 가능성을 추가한다.
@Test
fun calculateAddsValues1(@MockK car1: Car, @RelaxedMockK car2: Car) {
// ... use car1 and car2
}
Spy
스파이 모의과 실제 객체를 혼합 할 수 있다.
val car = spyk(Car()) // 또는 spyk<Car>()으로 디폴트 생성자를 호출한다.
car.drive(Direction.NORTH) // Car가 반환하는 실제 함수를 반환한다.
verify { car.drive(Direction.NORTH) }
confirmVerified(car)
참고 : 스파이 객체는 전달된 객체의 복사본이다.
Relaxed mock
relaxed mock모든 함수에 대해 간단한 값을 반환 모의이다. 따라서 각 케이스의 동작 지정을 생략하면서 필요한 것을 스텁 할 수 있다. 참조 형의 경우, 연쇄 모의가 반환된다.
val car = mockk<Car>(relaxed = true)
car.drive(Direction.NORTH) // returns null
verify { car.drive(Direction.NORTH) }
confirmVerified(car)
참고 : relaxed mock를 사용하는 경우, 반환 값이 제네릭이 잘 작동하지 않습니다. 일반적으로이 경우 클래스 캐스트 예외가 throw 된다. 반환 값이 제네릭이면 스텁을 수동으로 지정해야 한다.
해결 방법 :
val func = mockk<() -> Car>(relaxed = true) // 이 경우 invoke 함수는 반환 값에 제네릭이 있다
//이 라인은 해결 방법이다. 이 행이 없으면`relaxed mock`는 다음 줄에 클래스 캐스트 예외를 throw 한다
every { func() } returns Car() // 또는 예를 들어 mockk()을 반환 할 수 있다
func()
Unit을 반환하는 함수의 Relaxed mock (Mock relaxed for functions returning Unit)
Unit을 반환하는 함수를 Relaxed mock으로 하고 싶다면 mockk 함수, @MockK
어노테이션 또는 MockKAnntations.init
함수의 인수로 relaxUnitFun = true
을 사용할 수 있다.
mockk 함수 :
mockk<MockCls>(relaxUnitFun = true)
@MockK
어노테이션 :
@MockK(relaxUnitFun = true)
lateinit var mock1: RurfMockCls
init {
MockKAnnotations.init(this)
}
MockKAnntations.init
함수 :
@MockK
lateinit var mock2: RurfMockCls
init {
MockKAnnotations.init(this, relaxUnitFun = true)
}
객체 모형 (Object mocks)
객체는 다음과 같은 방법으로 모의로 변환 할 수 있다.
object MockObj {
fun add(a: Int, b: Int) = a + b
}
mockkObject(MockObj) // 모의 객체에 적용한다
assertEquals(3, MockObj.add(1, 2))
every { MockObj.add(1, 2) } returns 55
assertEquals(55, MockObj.add(1, 2))
취소는 unmockkAll
또는 unmockkObject
를 사용한다.
@Before
fun beforeTests() {
mockkObject(MockObj)
every { MockObj.add(1,2) } returns 55
}
@Test
fun willUseMockBehaviour() {
assertEquals(55, MockObj.add(1,2))
}
@After
fun afterTests() {
unmockkAll()
// or unmockkObject(MockObj)
}
Kotlin 언어의 제한에도 불구하고 테스트 로직에 필요한 경우 객체의 새 인스턴스를 만들 수 있다.
val newObjectMock = mockk<MockObj>()
클래스 모의 (Class mock)
때로는 어떤 클래스의 모의가 필요하다. 그런 경우에는 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) }
열거 모의 (Enumeration mocks)
열거 형은 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)
생성자 모의 (Constructor mocks)
경우에 따라서는 특히 소유하지 않은 코드에서는 새로 만든 객체를 모의해야한다. 이를 위해 다음 구성이 제공된다.
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)) // 새로운 객체가 생성되는 점에 유의하길 바란다
verify { anyConstructed<MockCls>().add(1, 2) }
기본적인 아이디어는 모의된 클래스의 생성자가 실행 된 직후에 객체 constructed mock가 될 것이다. 그런 모의 모의 동작은 anyConstructed<MockCls>()
로 표시되는 특별한 prototype mock 연결된다. 이러한 prototype mock클래스 당 하나의 인스턴스가 있다. 통화 기록은 prototype mock하지만 발생한다. 함수가 지정되지 않은 경우 원래 함수가 실행된다.
부분 인수 매칭 (Partial argument matching)
보통 인수와 매칭 모두를 혼합 할 수 있다.
val car = mockk<Car>()
every {
car.recordTelemetry(
speed = more(50),
direction = Direction.NORTH, // 여기에 "eq()"가 사용되었다.
lat = any(),
long = any()
)
} returns Outcome.RECORDED
obj.recordTelemetry(60, Direction.NORTH, 51.1377382, 17.0257142)
verify { obj.recordTelemetry(60, Direction.NORTH, 51.1377382, 17.0257142) }
confirmVerified(obj)
연쇄 호출 (Chained calls)
호출 체인을 스텁 할 수 있다.
val car = mockk<Car>()
every { car.door(DoorType.FRONT_LEFT).windowState() } returns WindowState.UP
car.door(DoorType.FRONT_LEFT) // Door 연쇄 모의를 반환한다
car.door(DoorType.FRONT_LEFT).windowState() // returns WindowState.UP
verify { car.door(DoorType.FRONT_LEFT).windowState() }
confirmVerified(car)
참고 : 함수의 반환 형식이 제네릭 인 경우 실제 형식에 대한 정보는 삭제됩니다. 연쇄 호출을 작동하려면 추가 정보가 필요한다. 대부분의 경우 프레임 워크는 캐스트 예외를 캐치하고 autohinting실행한다. 명시적으로 필요한 경우는 다음의 호출을 하기 전에 hint을 사용한다.
every { obj.op2(1, 2).hint(Int::class).op1(3, 4) } returns 5
계층적 모형 (Hierarchical mocking)
버전 1.9.1에서 모의 계층에 체인 수 있다.
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"
}
}
)
}
캡처 (Capturing)
CapturingSlot 또는 MutableList로 인수를 캡처 할 수 있다.
val car = mockk<Car>()
val slot = slot<Double>()
val list = mutableListOf<Double>()
every {
obj.recordTelemetry(
speed = capture(slot),
direction = Direction.NORTH
)
} answers {
println(slot.captured)
Outcome.RECORDED
}
every {
obj.recordTelemetry(
speed = capture(list),
direction = Direction.SOUTH
)
} answers {
println(list.captured())
Outcome.RECORDED
}
obj.recordTelemetry(speed = 15, direction = Direction.NORTH) // prints 15
obj.recordTelemetry(speed = 16, direction = Direction.SOUTH) // prints 16
verify(exactly = 2) { obj.recordTelemetry(speed = or(15, 16), direction = any()) }
confirmVerified(obj)
최소, 최대, 또는 정확한 횟수의 검증 (Verification atLeast, atMost or exactly times)
호출 카운트는 atLeast, atMost또는 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)
// 모든 통과한다
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) } // 호출되지 않았음을 의미한다
confirmVerified(car)
검증 순서 (Verification order)
- verifyAll순서를 확인하지 않고 모든 호출이 이루어 졌는지를 확인한다.
- verifySequence는 지정된 순서로 호출이 이루어 졌는지를 확인한다.
- verifyOrder호출이 특정 순서로 발생했는지 여부를 확인한다.
- wasNot Called은 모의 또는 모의 목록이 전혀 호출되지 않았음을 확인한다.
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)
검증 확인 (Verification confirmation)
verify...
구문에 의해 모든 호출이 검증된 것을 다시 확인하려면, confirmVerified
을 사용할 수 있다.
confirmVerified(mock1, mock2)
이러한 검증 방법은 검증 된 모든 호출을 망라하고 있기 때문에, verifySequence
그리고 verifyAll
을 사용하는 것은별로 의미가 없다.
몇 군데가 검증없이 남아있는 경우 예외를 throw
한다.
일부 호출은 이러한 확인에서 제외 될 수 있다. 자세한 내용은 다음 섹션을 확인한다.
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) // 모든 호출이 검증이 적용되었음을 확인한다
기록 제외 (Recording exclusions)
그다지 중요하지 않은 호출을 기록에서 제외하려면, excludeRecords
를 사용할 수 있다.
excludeRecords { mock.operation(any(), 5) }
일치하는 모든 통화 기록에서 제외된다. 이것은 verifyAll
, verifySequence
, 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)가 제외 된 때문에 car.drive(Direction.NORTH)에서만 확인할 수 있다.
확인 시간 (Verification timeout)
동시 작업을 확인하려면 timeout = xxx
을 사용할 수 있다.
mockk<MockCls> {
every { sum(1, 2) } returns 4
Thread {
Thread.sleep(2000)
sum(1, 2)
}.start()
verify(timeout = 3000) { sum(1, 2) }
}
이는 검증을 통과하거나 시간 제한에 도달하거나 하나의 상태가 될 때까지 기다린다.
Unit을 반환 (Returning Unit)
함수가 Unit
을 반환하는 경우는 just Runs
를 사용할 수 있다.
class MockedClass {
fun sum(a: Int, b: Int): Unit {
println(a + b)
}
}
val obj = mockk<MockedClass>()
every { obj.sum(any(), 3) } just Runs
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)
}
코루틴 (Coroutines)
코루틴을 모의하려면 지원 라이브러리에 다른 종속성을 추가해야 한다.
Gradle
testCompile "org.jetbrains.kotlinx:kotlinx-coroutines-core:x.x"
Maven
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-core</artifactId>
<version>x.x</version>
<scope>test</scope>
</dependency>
다음은 coEvery
, coVerify
, coMatch
, coAssert
, coRun
, coAnswers
또는 coInvoke
를 사용하여 중단 함수를 모의로 할 수 있다.
val car = mockk<Car>()
coEvery { car.drive(Direction.NORTH) } returns Outcome.OK
car.drive(Direction.NORTH) // returns OK
coVerify { car.drive(Direction.NORTH) }
확장 기능 (Extension functions)
확장 함수는 세 가지 경우가 있다.
- 전체 클래스 (class wide)
- 전체 객체 (object wide)
- 전체 모듈 (module wide)
객체와 클래스의 경우 일반적으로 모의하는 것만으로 확장 함수를 모의 할 수 있다.
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()
}
}
전체 모듈의 확장 기능을 모의하려면 모듈의 클래스 이름을 인수로 mockkStatic(...)
로 빌드해야 한다. 예를 들어, pkg
패키지 모듈 File.kt
의 "pkg.FileKt"
으로 하면 된다.
data class Obj(val value: Int)
// File.kt("pkg" 패키지)로 선언되어 있습니다
fun Obj.extensionFunc() = value + 5
mockkStatic("pkg.FileKt")
every {
Obj(5).extensionFunc()
} returns 11
assertEquals(11, Obj(5).extensionFunc())
verify {
Obj(5).extensionFunc()
}
@JvmName
를 사용하는 경우는 클래스 이름으로 지정한다.
KHttp.kt :
@file:JvmName("KHttp")
package khttp
// ... KHttp code
테스트 코드 :
mockkStatic("khttp.KHttp")
확장 함수를 모의하기 위해 좀 더 자세히 알 필요가 있는 경우가 있다. 예를 들어, File.endsWith()
확장 기능에는 전혀 예측할 수 없는 classname
이 있다.
mockkStatic("kotlin.io.FilesKt__UtilsKt")
every { File("abc").endsWith(any<String>()) } returns true
println(File("abc").endsWith("abc"))
이것은 예측 불가능한 표준 Kotlin 동작이다. [Tools]-> [Kotlin]->[Show Kotlin Bytecode]
를 사용하거나 JAR 아카이브에서 .class
파일을 확인하여 이러한 이름을 검색한다.
가변 인수 (Varargs)
버전 1.9.1에서 더욱 확장된 가변 인수 처리가 가능하게 되었다.
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)) // 6
개인 함수의 모의 / 동적 호출 (Private functions mocking / dynamic calls)
개인 함수를 모의 할 필요가 있는 경우에는 동적 호출을 통해 할 수 있다.
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"]()
}
개인 호출을 확인하는 경우는 recordPrivateCalls = true
에 spyk
를 작성해야 한다.
또한 자세한 구문은 같은 동적 호출과 함께 속성을 가져오고 설정할 수 있다.
val mock = spyk(Team(), recordPrivateCalls = true)
every { mock getProperty "speed" } returns 33
every { mock setProperty "acceleration" value less(5) } just runs
every { mock invokeReturnsUnit "privateMethod" } just runs
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") }
속성 백업 필드 (Property backing fields)
fieldValue를 통해 필드 백업 속성에 액세스하여 설정되는 값에 value 사용할 수 있다.
참고 : 다음 예제에서는 propertyType
을 사용하여 fieldValue
형식을 지정한다. 이것은 겟타 유형을 자동으로 캡처 할 수 있기 때문에 필요한다. nullablePropertyType
를 사용하여 null 허용 유형을 지정한다.
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
}
여러 인터페이스 (Multiple interfaces)
인터페이스를 통해 추가 동작을 추가하고 이를 스텁화 한다.
val spy = spyk(System.out, moreInterfaces = 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()
Mocking nothing
여기에 특별한 것은 아무것도 없다. Nothing을 반환하는 함수가 있는 경우 :
fun quit(status: Int): Nothing {
exitProcess(status)
}
다음으로, 예를 들어, 예외를 작동으로 발생 할 수 있다.
every { quit(1) } throws Exception("this is a test")
매칭의 확장성 (Matcher extensibility)
아주 간단한 방법은 MockKMatcherScope
또는 MockKVerificationScope
함수에 연결하고 match 함수를 사용하여 새 매칭를 만드는 것이다.
fun MockKMatcherScope.seqEq(seq: Sequence<String>) = match<Sequence<String>> {
it.toList() == seq.toList()
}
또한 Matcher 인터페이스를 구현하여 고급 매칭를 만들 수 있다.
설정 파일 (Settings file)
매개 변수를 전역으로 조정하려면 리소스 파일에서 일부 설정을 지정한다.
사용법 :
- 리소스 io/mockk/settings.properties파일을 만듭니다.
- 다음 옵션 중 하나를 입력한다.
relaxed=true|false
relaxUnitFun=true|false
recordPrivateCalls=true|false
DSL 테이블 (DSL tables)
DSL을 습득하는데 도움이 되는 몇 가지 표를 보여준다
최상위 함수 (Top level functions)
함수 | 설명 |
---|---|
mockk<T>(...) |
일반 모의한다. |
spyk<T>() |
기본 생성자를 사용하여 스파이를 구축한다. |
spyk(obj) |
obj복사하여 스파이를 구축한다. |
slot |
캡처 슬롯을 만듭니다 |
every |
스텁 블록을 시작한다. |
coEvery |
코루틴 스텁 블록을 시작한다. |
verify |
검증 블록을 시작한다. |
coVerify |
코루틴 검증 블록을 시작한다. |
verifyAll |
모든 호출을 포함한 검증 블록을 시작한다. |
coVerifyAll |
코루틴의 모든 호출을 포함한 검증 블록을 시작한다. |
verifyOrder |
순서를 확인하는 검증 블록을 시작한다. |
coVerifyOrder |
코루틴 순서를 확인하는 검증 블록을 시작한다. |
verifySequence |
모든 호출이 지정된 순서로 발생했는지 여부를 확인하는 검증 블록을 시작한다. |
coVerifySequence |
코루틴의 모든 호출이 지정된 순서로 발생했는지 여부를 확인하는 검증 블록을 시작한다. |
excludeRecords |
호출에서 일부 기록을 제외 |
confirmVerified |
기록 된 모든 호출이 검증 된 것을 확인한다. |
clearMocks |
지정된 모의을 지운다. |
registerInstanceFactory |
특정 객체의 인스턴스화 방법을 다시 정의 할 수 있다 |
mockkClass |
클래스를 매개 변수로 전달하여 일반 모의한다. |
mockkObject |
모든 객체를 객체의 모의하거나 이미 변환 된 경우 취소한다. |
unmockkObject |
객체 모형을 일반 객체로 되돌린다 |
mockkStatic |
클래스에서 정적 모의하거나 이미 변환 된 경우 취소한다. |
unmockkStatic |
정적 모의을 정규 수업으로 되돌린다 |
clearStaticMockk |
정적 모의을 지운다 |
mockkConstructor |
생성자 모의 클래스에서 분리하거나 이미 변환 된 경우 취소한다. |
unmockkConstructor |
생성자 모의을 정규 수업으로 되돌린다 |
clearConstructorMockk |
생성자의 모의를 지운다 |
unmockkAll |
객체 모의 정적 모의 생성자 모의 안못쿠한다. |
clearAllMocks |
일반 모의 객체 모의 정적 모의 생성자 모의을 지운다 |
매칭 (Matchers)
기본적으로 간단한 인수 eq()
를 사용하여 일치된다.
매칭 | 설명 |
---|---|
any() |
모든 인수와 일치한다. |
allAny() |
간단한 인수로 제공되는 매칭에 eq()대신 any()사용하는 특별한 매칭이다. |
isNull() |
값이 null인지 여부를 확인한다. |
isNull(inverse=true) |
값이 null 있는지 확인한다. |
ofType(type) |
값이 유형에 속하는지 여부를 확인한다. |
match { it.startsWith("string") } |
전달 된 술어를 통해 일치한다. |
coMatch { it.startsWith("string") } |
전달 된 코루틴 술어를 통해 일치한다. |
matchNullable { it?.startsWith("string") } |
전달 된 술어를 통해 null 허용 값과 일치한다. |
coMatchNullable { it?.startsWith("string") } |
전달 된 코루틴 술어를 통해 null 허용 값과 일치한다. |
eq(value) |
값이 deepEquals함수를 통해 제공된 값과 같으면 일치한다. |
eq(value, inverse=true) |
값이 deepEquals 함수를 통해 제공된 값과 같지 않으면 일치한다. |
neq(value) |
값이 deepEquals함수를 통해 제공된 값과 같지 않으면 일치한다. |
refEq(value) |
값이 참조 비교에 의해 제공된 값과 같으면 일치한다. |
refEq(value, inverse=true) |
값이 참조 비교에 의해 제공된 값과 같지 않으면 일치한다. |
nrefEq(value) |
값이 참조 비교에 의해 제공된 값과 같지 않으면 일치한다. |
cmpEq(value) |
값이 compareTo 함수에 제공된 값과 같으면 일치한다. |
less(value) |
값이 compareTo 함수에 지정된 값보다 작은 경우에 일치한다. |
more(value) |
값이 compareTo 함수에 제공된 값보다 큰 경우에 일치한다. |
less(value, andEquals=true) |
값이 compareTo 함수에 지정된 값 이하인 경우에 일치한다. |
more(value, andEquals=true) |
값이 compareTo 함수에 지정된 값 이상인 경우에 일치한다. |
range(from, to, fromInclusive=true, toInclusive=true) |
compareTo 함수를 통해 값이 범위 내에있는 경우에 일치한다. |
and(left, right) |
논리적으로 두 매칭를 결합한다. |
or(left, right) |
논리합에서 두 매칭를 결합한다. |
not(matcher) |
매칭을 해제한다. |
capture(slot) |
CapturingSlot값을 캡처한다. |
capture(mutableList) |
값을 목록에 캡처한다. |
captureNullable(mutableList) |
null 값과 함께 값을 목록에 캡처한다. |
captureLambda() |
람다를 캡처한다. |
captureCoroutine() |
코루틴를 캡처한다. |
invoke(...) |
일치하는 인수를 호출한다. |
coInvoke(...) |
코루틴 일치하는 인수를 호출한다. |
hint(cls) |
삭제 된 경우에 대비하여 다음의 반환 유형을 나타냅니다 |
anyVararg() |
가변 인수의 모든 요소와 일치한다. |
varargAny(matcher) |
하나의 요소가 매칭에 일치하는 경우 일치한다. |
varargAll(matcher) |
모든 요소가 매칭에 일치하는 경우 일치한다. |
any...Vararg() |
가변 인수의 모든 요소와 일치한다. (기본 형식 별) |
varargAny...(matcher) |
하나의 요소가 매칭에 일치하는 경우 일치한다. (기본 형식 별) |
varargAll...(matcher) |
모든 요소가 매칭에 일치하는 경우 일치한다. (기본 형식 별) |
검증 모드에서만 사용 가능한 특별한 매칭이 몇 가지 있다.
매칭 | 설명 |
---|---|
withArg { code } |
임의의 값과 일치하고 코드의 실행을 허용한다. |
withNullableArg { code } |
null 값을 허용하는 값과 일치하고 코드의 실행을 허용한다. |
coWithArg { code } |
임의의 값과 일치하고 코 루틴 코드를 실행할 수 있다 |
coWithNullableArg { code } |
null 값을 허용하는 값과 일치하고 코 루틴 코드를 실행할 수 있다 |
유효성 체크 (Validators)
유효성 체크 | 설명 |
---|---|
verify { mock.call() } |
호출이 실행 된 것을 순서로 확인한다. |
verify(inverse=true) { mock.call() } |
호출이 실행되지 않은 것을 순서로 확인한다. |
verify(atLeast=n) { mock.call() } |
호출이 최소한 n 번 실행 된 것을 순서로 확인한다. |
verify(atMost=n) { mock.call() } |
호출이 최대 n 번 실행 된 것을 순서로 확인한다. |
verify(exactly=n) { mock.call() } |
호출이 정확히 n 번 실행 된 것을 순서로 확인한다. |
verifyAll { mock.call1(); mock.call2() } |
언급 된 모의에 지정된 호출 만 실행 된 것을 순서로 확인한다. |
verifyOrder { mock.call1(); mock.call2() } |
지정한 순서대로 호출이 차례로 이루어 졌는지 확인한다. |
verifySequence { mock.call1(); mock.call2() } |
언급 된 모의에 대해 지정된 일련의 호출 만이 수행되었음을 확인한다. |
verify { mock wasNot Called } |
모의가 호출되지 않았 음을 확인한다. |
verify { listOf(mock1, mock2) wasNot Called } |
모의 목록이 호출되지 않았 음을 확인한다. |
응답 (Answers)
응답 후에 하나 이상의 추가 응답이 계속되는 경우가 있다.
도움말 | 설명 |
---|---|
returns value |
일치하는 호출이 지정된 값을 반환하도록 지정한다. |
returnsMany list |
일치하는 호출 목록에서 값을 반환 후속 호출이 다음의 요소를 반환하도록 지정한다. |
throws ex |
일치하는 호출이 예외를 슬로우하는 것을 지정한다. |
answers { code } |
일치하는 호출 answer scope을하는 코드 블록으로 응답하도록 지정한다. |
coAnswers { code } |
일치 한 호출 answer scope을 가진 코 루틴 코드 블록으로 응답하도록 지정한다. |
answers answerObj |
일치하는 호출 Answer 객체에 응답하도록 지정한다. |
answers { nothing } |
일치하는 호출이 null로 응답하도록 지정한다. |
just Runs |
일치하는 호출이 Unit을 반환하도록 지정한다. (null 를 반환한다) |
propertyType Class |
지원 필드 접근 자 유형을 지정한다. |
nullablePropertyType Class |
지원 필드 접근의 형태를 null 허용 형식으로 지정한다. |
추가 응답 (Additional answer)
결과적으로 생기는 각 호출에서 다음 응답을 반환, 마지막 값이 유지된다. 이것은 returnsMany의미와 비슷한다.
추가 도움말 | 설명 |
---|---|
andThen value |
일치하는 호출이 하나의 지정된 값을 반환하도록 지정한다. |
andThenMany list |
일치하는 호출 목록에서 값을 돌려 다음의 요소가 반환 될 때마다 반환하도록 지정한다. |
andThenThrows ex |
일치하는 호출이 예외를 슬로우하는 것을 지정한다. |
andThen { code } |
일치하는 호출 answer scope에서 범위 된 코드 블록에 응답하도록 지정한다. |
coAndThen { code } |
일치하는 호출 answer scope에서 범위 된 코 루틴 코드 블록으로 응답하도록 지정한다. |
andThenAnswer answerObj |
일치하는 호출 Answer 객체에 응답하도록 지정한다. |
andThen { nothing } |
일치하는 호출이 null로 응답하도록 지정한다. |
응답 범위 (Answer scope)
매개 변수 | 설명 |
---|---|
call |
호출 및 매칭으로 구성된 호출 객체 |
invocation |
호출 된 실제 함수에 대한 정보가 포함되어 있다 |
matcher |
호출의 조합에 사용되는 매칭 대한 정보가 포함되어 있다 |
self |
호출 된 객체를 참조한다. |
method |
호출 된 함수를 참조한다. |
args |
호출 인수를 참조한다. |
nArgs |
호출 인수의 수 |
arg(n) |
n 번째의 인수 |
firstArg() |
첫 번째 인수 |
secondArg() |
두 번째 인수 |
thirdArg() |
셋째 인수 |
lastArg() |
마지막 인수 |
captured() |
목록으로 캡처 할 때 편리한 목록의 마지막 요소 |
lambda<...>().invoke() |
캡처 된 람다를 호출 |
coroutine<...>().coInvoke() |
캡처 된 코루틴를 호출 |
nothing |
대답은 아무것도 돌려주지 않는 경우는 null 값 |
fieldValue |
속성 백업 필드에 접근 |
fieldValueAny |
Any?형태를 가지는 속성 백업 필드에 접근 |
value |
속성 백업 필드와 같은 형태로 캐스팅 된 값 |
valueAny |
Any?형태로 설정되어 있는 값 |
가변 인수 범위 (Vararg scope)
매개 변수 | 설명 |
---|---|
position |
가변 인수 배열 인수의 위치 |
nArgs |
가변 인수 배열 인수의 총 |
출처
- 공식 문서: https://mockk.io/