MockK
一言で表すと
mocking library for Kotlin
概要
DSLでの例
code:kotlin
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)
Annotationでの例
code:kotlin
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
}
}
Mori Atsushi.icon 僕はDSLが好きです
Spy
実際のオブジェクトとmockをmixしたいときに使う
code:kotlin
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)
Relaxed mock
全ての関数に対してシンプルな値を返すモック
code:kotlin
val car = mockk<Car>(relaxed = true)
car.drive(Direction.NORTH) // returns null
verify { car.drive(Direction.NORTH) }
confirmVerified(car)
Mori Atsushi.icon relaxUnitFun を使うとUnitだけ自動mockしてくれるので、こっちのほうがよく使う
Partial mocking
mockに対して部分的にオリジナルの処理を呼び出すことができる
code:kotlin
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
Mori Atsushi.icon こういうことやりだすと混乱しそう 😇
horis.icon これいるのか..
Mock relaxed for functions returning Unit
Relax mockでUnitを返す関数を使いたい場合、relaxUnitFun = true を設定する
code:kotlin
mockk<ClassBeingMocked>(relaxUnitFun = true)
@MockK(relaxUnitFun = true)
lateinit var mock1: ClassBeingMocked
init {
MockKAnnotations.init(this)
}
@MockK
lateinit var mock2: ClassBeingMocked
init {
MockKAnnotations.init(this, relaxUnitFun = true)
}
Object mocks
Kotlinのobjectもモック可能
code:kotlin
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))
戻すには unmockkAll または unmockkObject を使う
Mori Atsushi.icon 戻し忘れると連続すると動くけど、単体だと動かんとかわけわからんことが発生する
code:kotlin
@Before
fun beforeTests() {
mockkObject(ObjBeingMocked)
every { MockObj.add(1,2) } returns 55
}
@Test
fun willUseMockBehaviour() {
assertEquals(55, ObjBeingMocked.add(1,2))
}
@After
fun afterTests() {
unmockkAll()
// or unmockkObject(ObjBeingMocked)
}
enumもこれを使う
chigichan24.icon みんな大好き object mock
Constructor mocks
コンストラクタをモックできる
mayamito.icon !?
chigichan24.icon 使用用途不明 Part2
Mori Atsushi.icon DIしてないときに使えたりする
Mori Atsushi.icon constructorをmockkしてもconstructorは呼ばれるので注意が必要だった
code:kotlin
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)
}
気になるポイント
コメント