Skip to content

Commit

Permalink
Merge pull request #70 from nhaarman/release-0.6.1
Browse files Browse the repository at this point in the history
Release 0.6.1
  • Loading branch information
nhaarman committed Sep 9, 2016
2 parents d07a2c9 + 650e293 commit f18d86e
Show file tree
Hide file tree
Showing 11 changed files with 72 additions and 116 deletions.
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ install:

script:
- ./gradlew test

notifications:
email: false
105 changes: 17 additions & 88 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,96 +17,25 @@ dependencies {
}
```

## Examples
## Example

### Creating mock instances

Due to Kotlin's [reified type parameters](https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters), if the type can be inferred, you don't have to specify it explicitly:

**Java**:
```java
MyClass c = mock(Myclass.class);
c.doSomething(mock(MyOtherClass.class));
```

**Kotlin**:
```kotlin
val c : MyClass = mock()
c.doSomething(mock())
```

If the type can't be inferred, you can pass it like so:

```kotlin
val d = mock<MyClass>()
```


### Expecting any value

Mockito's `any(Class<T>)` often returns `null` for non-primitive classes.
In Kotlin, this can be a problem due to its [null-safety](https://kotlinlang.org/docs/reference/null-safety.html) feature.
This library creates non-null instances when necessary.
Again, if the type can be inferred, you don't have to specify it explicitely:

**Java**:
```java
verify(myClass).doSomething(any(String.class));
```

**Kotlin**:
```kotlin
verify(myClass).doSomething(any()); // Non-nullable parameter type is inferred
```

For generic arrays, use the `anyArray()` method:

```kotlin
verify(myClass).setItems(anyArray())
```

## Custom instance creators

There are some cases where Mockito-Kotlin cannot create an instance of a class.
This can for instance be when a constructor has some specific preconditions
for its parameters.
You can _register_ `instance creators` to overcome this:

```kotlin
MockitoKotlin.registerInstanceCreator<MyClass> { MyClass(5) }
```

Whenever MockitoKotlin needs to create an instance of `MyClass`, this function is called,
giving you ultimate control over how these instances are created.

These instance creators work on a per-file basis: for each of your test files
you will need to register them again.

### Argument Matchers

Using higher-order functions, you can write very clear expectations about expected values.
For example:

**Kotlin**:
```kotlin
verify(myClass).setItems(argThat{ size == 2 })
```

### Argument Captors

Argument Captors can be used to capture argument values for further assertions.
For example:
A test using Mockito-Kotlin typically looks like the following:

```kotlin
verify(myClass).setItems(capture { items ->
assertEquals(2, items.size)
assertEquals("test", items[0])
})
@Test
fun a(){
/* Given */
val mock = mock<MyClass> {
on { getText() } doReturn "text"
}
val classUnderTest = ClassUnderTest(mock)

/* When */
classUnderTest.doAction()

/* Then */
verify(mock).doSomething(any())
}
```

### Convenience functions

Most of Mockito's static functions are available as top-level functions.
That means, IDE's like IntelliJ can easily import and autocomplete them, saving you the hassle of manually importing them.


For more info and samples, see the [Wiki](https://github.com/nhaarman/mockito-kotlin/wiki).
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
plugins {
id "com.jfrog.bintray" version "1.5"
id "com.jfrog.bintray" version "1.7.1"
id 'com.github.ben-manes.versions' version '0.13.0'
}
apply plugin: 'maven'
apply plugin: 'maven-publish'
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-3.0-all.zip
4 changes: 2 additions & 2 deletions mockito-kotlin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ repositories {
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "org.mockito:mockito-core:2.0.99-beta"
compile "org.mockito:mockito-core:2.1.0-beta.125"

/* Tests */
testCompile "junit:junit:4.12"
testCompile "com.nhaarman:expect.kt:0.5.1"
testCompile "com.nhaarman:expect.kt:0.6.0"
}

publishing {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ fun <T : Any> createInstance(kClass: KClass<T>): T {
kClass.isPrimitive() -> kClass.toDefaultPrimitiveValue()
kClass.isEnum() -> kClass.java.enumConstants.first()
kClass.isArray() -> kClass.toArrayInstance()
kClass.isClassObject() -> kClass.toClassObject()
kClass.isClassObject() -> kClass.toClassObject()
else -> kClass.easiestConstructor().newInstance()
}
}
Expand All @@ -68,20 +68,14 @@ fun <T : Any> createInstance(kClass: KClass<T>): T {
* Tries to find the easiest constructor which it can instantiate.
*/
private fun <T : Any> KClass<T>.easiestConstructor(): KFunction<T> {
return constructors.firstOrDefault(
{
it.parameters.filter {
it.type.toString().toLowerCase().contains("array")
}.isEmpty()
},
{
constructors.sortedBy { it.parameters.size }.first()
}
)
return constructors
.sortedBy { it.parameters.size }
.withoutArrayParameters()
.firstOrNull() ?: constructors.sortedBy { it.parameters.size }.first()
}

private fun <T> Collection<T>.firstOrDefault(predicate: (T) -> Boolean, default: () -> T): T {
return firstOrNull(predicate) ?: default()
private fun <T> List<KFunction<T>>.withoutArrayParameters() = filter {
it.parameters.filter { parameter -> parameter.type.toString().toLowerCase().contains("array") }.isEmpty()
}

@Suppress("SENSELESS_COMPARISON")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,8 @@ import kotlin.reflect.KClass
fun after(millis: Long) = Mockito.after(millis)

inline fun <reified T : Any> any() = Mockito.any(T::class.java) ?: createInstance<T>()
inline fun <reified T : Any> anyArray(): Array<T> = Mockito.any(Array<T>::class.java) ?: arrayOf()
inline fun <reified T : Any> anyCollection(): Collection<T> = Mockito.anyCollectionOf(T::class.java)
inline fun <reified T : Any> anyList(): List<T> = Mockito.anyListOf(T::class.java)
inline fun <reified T : Any> anySet(): Set<T> = Mockito.anySetOf(T::class.java)
inline fun <reified K : Any, reified V : Any> anyMap(): Map<K, V> = Mockito.anyMapOf(K::class.java, V::class.java)
inline fun <reified T : Any> anyVararg() = Mockito.anyVararg<T>() ?: createInstance<T>()

inline fun <reified T : Any?> anyArray(): Array<T> = Mockito.any(Array<T>::class.java) ?: arrayOf()
inline fun <reified T : Any> anyVararg(): T = Mockito.any<T>() ?: createInstance<T>()
inline fun <reified T : Any> argThat(noinline predicate: T.() -> Boolean) = Mockito.argThat<T> { it -> (it as T).predicate() } ?: createInstance(T::class)

fun atLeast(numInvocations: Int): VerificationMode = Mockito.atLeast(numInvocations)!!
Expand All @@ -71,8 +66,8 @@ fun ignoreStubs(vararg mocks: Any): Array<out Any> = Mockito.ignoreStubs(*mocks)
fun inOrder(vararg mocks: Any): InOrder = Mockito.inOrder(*mocks)!!

inline fun <reified T : Any> isA(): T? = Mockito.isA(T::class.java)
inline fun <reified T : Any> isNotNull(): T? = Mockito.isNotNull(T::class.java)
inline fun <reified T : Any> isNull(): T? = Mockito.isNull(T::class.java)
fun <T : Any> isNotNull(): T? = Mockito.isNotNull()
fun <T : Any> isNull(): T? = Mockito.isNull()

inline fun <reified T : Any> mock(): T = Mockito.mock(T::class.java)!!
inline fun <reified T : Any> mock(defaultAnswer: Answer<Any>): T = Mockito.mock(T::class.java, defaultAnswer)!!
Expand All @@ -93,7 +88,7 @@ inline infix fun <reified T> OngoingStubbing<T>.doReturn(ts: List<T>): OngoingSt

fun mockingDetails(toInspect: Any): MockingDetails = Mockito.mockingDetails(toInspect)!!
fun never(): VerificationMode = Mockito.never()!!
inline fun <reified T : Any> notNull(): T? = Mockito.notNull(T::class.java)
fun <T : Any> notNull(): T? = Mockito.notNull()
fun only(): VerificationMode = Mockito.only()!!
fun <T> refEq(value: T, vararg excludeFields: String): T? = Mockito.refEq(value, *excludeFields)

Expand All @@ -115,3 +110,15 @@ fun verifyZeroInteractions(vararg mocks: Any) = Mockito.verifyZeroInteractions(*

fun <T> whenever(methodCall: T): OngoingStubbing<T> = Mockito.`when`(methodCall)!!
fun withSettings(): MockSettings = Mockito.withSettings()!!

@Deprecated("Use any() instead.", ReplaceWith("any()"))
inline fun <reified T : Any> anyCollection(): Collection<T> = any()

@Deprecated("Use any() instead.", ReplaceWith("any()"))
inline fun <reified T : Any> anyList(): List<T> = any()

@Deprecated("Use any() instead.", ReplaceWith("any()"))
inline fun <reified T : Any> anySet(): Set<T> = any()

@Deprecated("Use any() instead.", ReplaceWith("any()"))
inline fun <reified K : Any, reified V : Any> anyMap(): Map<K, V> = any()
1 change: 1 addition & 0 deletions mockito-kotlin/src/test/kotlin/Classes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ interface Methods {
fun intArray(i: IntArray)
fun closed(c: Closed)
fun closedArray(a: Array<Closed>)
fun closedNullableArray(a: Array<Closed?>)
fun closedCollection(c: Collection<Closed>)
fun closedList(c: List<Closed>)
fun closedStringMap(m: Map<Closed, String>)
Expand Down
13 changes: 13 additions & 0 deletions mockito-kotlin/src/test/kotlin/CreateInstanceTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,15 @@ class CreateInstanceTest {
}
}

@Test
fun defaultEmptyConstructor_takesSimplestConstructor() {
/* When */
val result = createInstance(WithDefaultEmptyConstructor::class)

/* Then */
expect(result).toNotBeNull()
}

private class PrivateClass private constructor(val data: String)

class ClosedClass
Expand Down Expand Up @@ -459,5 +468,9 @@ class CreateInstanceTest {
}
}

class WithDefaultEmptyConstructor() {
constructor(c: ForbiddenConstructor) : this()
}

enum class MyEnum { VALUE, ANOTHER_VALUE }
}
2 changes: 1 addition & 1 deletion mockito-kotlin/src/test/kotlin/MockitoKotlinTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,6 @@ class MockitoKotlinTest {
val result = createInstance<Closed>()

/* Then */
expect(result).toNotBeReferentially(closed)
expect(result).toNotBeTheSameAs(closed)
}
}
8 changes: 8 additions & 0 deletions mockito-kotlin/src/test/kotlin/MockitoTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ class MockitoTest {
}
}

@Test
fun anyNullableClassArray() {
mock<Methods>().apply {
closedNullableArray(arrayOf(Closed(), null))
verify(this).closedNullableArray(anyArray())
}
}

@Test
fun anyCollectionOfClosed() {
mock<Methods>().apply {
Expand Down

0 comments on commit f18d86e

Please sign in to comment.