Skip to content

Commit

Permalink
Merge pull request #816 from jonapoul/master
Browse files Browse the repository at this point in the history
Added a JUnit 4 rule
  • Loading branch information
Raibaz committed May 4, 2022
2 parents 9aa36ac + 5b6fe78 commit a1ed737
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 0 deletions.
24 changes: 24 additions & 0 deletions README.md
Expand Up @@ -190,6 +190,30 @@ To change this, use `overrideValues = true`. This would assign the value even if
To inject `val`s, use `injectImmutable = true`. For a shorter notation use `@OverrideMockKs` which does the same as
`@InjectMockKs` by default, but turns these two flags on.

### JUnit4

JUnit 4 exposes a rule-based API to allow for some automation following the test lifecycle. MockK includes a rule which uses this to set up and tear down your mocks without needing to manually call `MockKAnnotations.init(this)`. Example:

```kotlin
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
}
}
```

#### JUnit5

In JUnit5 you can use `MockKExtension` to initialize your mocks.
Expand Down
1 change: 1 addition & 0 deletions mockk/jvm/build.gradle.kts
Expand Up @@ -20,6 +20,7 @@ dependencies {
implementation(Deps.Libs.kotlinReflect(kotlinVersion()))
compileOnly(Deps.Libs.kotlinCoroutinesCore())
compileOnly("org.slf4j:slf4j-api:1.7.26")
compileOnly("junit:junit:4.13.1")

testImplementation(Deps.Libs.kotlinCoroutinesCore())
}
Expand Down
44 changes: 44 additions & 0 deletions mockk/jvm/src/main/kotlin/io/mockk/junit4/MockKRule.kt
@@ -0,0 +1,44 @@
package io.mockk.junit4

import io.mockk.MockKAnnotations
import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.RelaxedMockK
import io.mockk.unmockkAll
import org.junit.rules.TestRule
import org.junit.rules.TestWatcher
import org.junit.runner.Description

/**
* A simple JUnit 4 rule which handles the setting up and tearing down of mock objects using the
* [MockK] or [RelaxedMockK] annotations at the beginning and end of each test respectively -
* without needing to manually call [unmockkAll] or [MockKAnnotations.init].
*
* Example:
*
* ```
* class ExampleTest {
* @get:Rule
* val mockkRule = MockKRule(this)
*
* @MockK
* private lateinit var car: Car
*
* @Test
* fun something() {
* every { car.drive() } just runs
* ...
* }
* }
* ```
*/
class MockKRule(private val testSubject: Any) : TestWatcher(), TestRule {
override fun starting(description: Description?) {
super.starting(description)
MockKAnnotations.init(testSubject)
}

override fun finished(description: Description?) {
super.finished(description)
unmockkAll()
}
}
87 changes: 87 additions & 0 deletions mockk/jvm/src/test/kotlin/io/mockk/junit4/MockKRuleTest.kt
@@ -0,0 +1,87 @@
@file:Suppress("UNUSED_PARAMETER")

package io.mockk.junit4

import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.RelaxedMockK
import io.mockk.impl.annotations.SpyK
import io.mockk.verify
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import kotlin.test.assertEquals
import kotlin.test.assertNull
import kotlin.test.assertTrue

class MockKRuleTest {

@get:Rule
val mockkRule = MockKRule(this)

enum class Direction {
NORTH,
SOUTH,
EAST,
WEST
}

enum class Outcome {
FAILURE,
RECORDED
}

class RelaxedOutcome

class Car {
fun recordTelemetry(speed: Int, direction: Direction, lat: Double, long: Double): Outcome {
return Outcome.FAILURE
}

fun relaxedTest(): RelaxedOutcome? {
return null
}
}

@MockK
private lateinit var car: Car

@RelaxedMockK
private lateinit var relaxedCar: Car

@SpyK
private var carSpy = Car()

@Test
fun injectsValidMockInClass() {
every {
car.recordTelemetry(
speed = more(50),
direction = Direction.NORTH,
lat = any(),
long = any()
)
} returns Outcome.RECORDED

val result = car.recordTelemetry(51, Direction.NORTH, 1.0, 2.0)

assertEquals(Outcome.RECORDED, result)
}

@Test
fun injectsValidRelaxedMockInClass() {
val result = relaxedCar.relaxedTest()

assertTrue(result is RelaxedOutcome)
}

@Test
fun testInjectsValidSpyInClass() {
val result = carSpy.relaxedTest()

assertNull(result)

verify { carSpy.relaxedTest() }
}
}

0 comments on commit a1ed737

Please sign in to comment.