-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Kotlin 1.9.22 && moved documentation to kosi-libs.org
- Loading branch information
1 parent
50e8df4
commit 71b7595
Showing
14 changed files
with
836 additions
and
773 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,5 +4,5 @@ plugins { | |
|
||
allprojects { | ||
group = "org.kodein.mock" | ||
version = "1.16.0" | ||
version = "1.17.0" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
name: mockmp | ||
title: MocKMP | ||
version: '1.17' | ||
display_version: '1.17.0' | ||
nav: | ||
- modules/ROOT/nav.adoc | ||
asciidoc: | ||
attributes: | ||
version: '1.17.0' | ||
kotlin: '1.9.22' | ||
jdk: '11' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
* xref:index.adoc[Introduction] | ||
* xref:getting-started.adoc[Getting Started] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
= Getting started | ||
|
||
1. Apply the Gradle plugin and activate the helper dependency: | ||
+ | ||
[source,kotlin,subs="verbatim,attributes"] | ||
---- | ||
plugins { | ||
kotlin("multiplatform") | ||
id("org.kodein.mock.mockmp") version "{version}" | ||
} | ||
kotlin { | ||
// Your Koltin/Multiplatform configuration | ||
} | ||
|
||
mockmp { | ||
usesHelper = true | ||
installWorkaround() | ||
} | ||
---- | ||
|
||
2. Create a test class that declares injected mocks and fakes: | ||
+ | ||
[source,kotlin] | ||
---- | ||
class MyTest : TestsWithMocks() { | ||
override fun setUpMocks() = injectMocks(mocker) //<1> | ||
@Mock lateinit var view: View | ||
@Fake lateinit var model: Model | ||
val controller by withMocks { Controller(view = view, firstModel = model) } | ||
@Test fun controllerTest() { | ||
every { view.render(isAny()) } returns true | ||
controller.start() | ||
verify { view.render(model) } | ||
} | ||
} | ||
---- | ||
<1> This is mandatory and cannot be generated. You need to run the KSP generation at least once for your IDE to see the `injectMocks` generated function. | ||
+ | ||
NOTE: Every property annotated by `@Mock`, annotated by `@Fake` or delegated to `withMocks` will be reset fresh between each test. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
= MocKMP | ||
|
||
A Kotlin/Multiplatform Kotlin Symbol Processor that generates Mocks & Fakes at compile-time. | ||
|
||
[IMPORTANT] | ||
==== | ||
- Mocking only applies to *interfaces* | ||
- Faking only applies to *concrete trees* | ||
==== | ||
|
||
A Mock is an object implementing an interface whose behaviour is configurable at run-time, usually specifically for unit-tests. + | ||
A mocks can be used to validate that a method or property was (or wasn't) accessed a certain number of times. | ||
|
||
A fake is a concrete class that contains bogus data: all nullables are null, all strings are empty, all numbers are 0. + | ||
A fake can be used when you need to instanciate a class to test an API but do not care about the data it contains. | ||
|
||
[NOTE] | ||
==== | ||
MocKMP uses https://github.com/google/ksp[KSP], which has limited support for Kotlin/Multiplatform. | ||
In particular, https://github.com/google/ksp/issues/567[KSP does not support generating code for commonTest]. | ||
In order to work on Kotlin/Multiplatform projects, the MocKMP plugin uses a trick that consist of only generating code for the JVM, and then using the generated code for all targets. | ||
==== |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
* xref:setup.adoc[Setup] | ||
* xref:mocking.adoc[] | ||
* xref:facking.adoc[] | ||
* xref:injection.adoc[] | ||
* xref:helper.adoc[] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
= Faking concrete classes | ||
|
||
CAUTION: Only *concrete trees* (concrete classes containing concrete classes) can be faked! | ||
|
||
*Data classes* are ideal candidates for faking. | ||
|
||
|
||
== Requesting generation | ||
|
||
You can declare that a class needs a specific faked data by using the `@UsesFakes` annotation. | ||
|
||
[source,kotlin] | ||
---- | ||
@UsesFakes(User::class) | ||
class MyTests | ||
---- | ||
|
||
Once a type appears in `@UsesFakes`, the processor will generate a fake function for it. | ||
|
||
|
||
== Instantiating | ||
|
||
Once a class has been faked, you can get a new instance by calling its `fake*` corresponding function: | ||
|
||
[source,kotlin] | ||
---- | ||
@UsesFakes(User::class) | ||
class MyTests { | ||
val user = fakeUser() | ||
} | ||
---- | ||
|
||
Here are the rules the processor uses to generate fakes: | ||
|
||
* Nullable values are always `null`. | ||
* `Boolean` values are set to `false`. | ||
* Numeric values are set to `0`. | ||
* `String` values are set to empty `""`. | ||
* Other non-nullable non-primitive values are faked. | ||
|
||
[TIP] | ||
==== | ||
By using a `data class`, you can easily tweak your fakes according to your needs: | ||
[source,kotlin] | ||
---- | ||
val user = fakeUser().copy(id = 42) | ||
---- | ||
==== | ||
|
||
|
||
== Providing fake instances | ||
|
||
Classes that do not have a public constructor cannot be automatically faked. | ||
For these types, you need to provide your custom fake provider with `@FakeProvider`: | ||
|
||
[source,kotlin] | ||
---- | ||
@FakeProvider | ||
fun provideFakeInstant() = Instant.fromEpochSeconds(0) | ||
---- | ||
|
||
CAUTION: There can be only one provider per type, and it needs to be a top-level function. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
= The test class helper | ||
|
||
MocKMP provides the `TestsWithMocks` helper class that your test classes can inherit from. | ||
It provides the following benefits: | ||
|
||
- Provides a `Mocker`. | ||
- Resets the `Mocker` before each tests. | ||
- Provides `withMocks` property delegates to initialize objects with mocks. | ||
- Allows to call `every`, `everySuspending`, `verify`, and `verifyWithSuspend` without `mocker.`. | ||
It does not come with the standard runtime (as it forces the dependency to JUnit on the JVM), so to use it you need to either: | ||
|
||
* define `usesHelper = true` in the MocKMP Gradle plulgin configuration block, | ||
* or add the `mockmp-test-helper` implementation dependency. | ||
Here's a test class example with `TestsWithMocks`: | ||
|
||
[source,kotlin] | ||
---- | ||
@UsesFakes(User::class) | ||
class MyTests : TestsWithMocks() { //<1> | ||
override fun setUpMocks() = injectMocks(mocker) //<2> | ||
@Mock lateinit var db: Database | ||
@Mock lateinit var api: API | ||
@Fake lateinit var user: User | ||
val controller by withMocks { ControllerImpl(db, api) } //<3> | ||
@Test fun controllerTest() { | ||
every { view.render(isAny()) } returns true //<4> | ||
controller.start() | ||
verify { view.render(model) } //<4> | ||
} | ||
} | ||
---- | ||
<1> The class inherits `TestsWithMocks`, which provides helpers. | ||
<2> `setUpMocks` must be overriden, and can generally be just a delegation to the `injectMocks` generated function. | ||
<3> Controller will be (re)created before each tests with the new mock dependencies. | ||
<4> Note the absence of `mocker.` as you can use `every` and `verify` directly. | ||
|
||
NOTE: Properties delegated to `withMocks` will be (re)initialized *before each tests*, after the mocks have been (re)injected. | ||
|
||
[CAUTION] | ||
==== | ||
Because of https://youtrack.jetbrains.com/issue/KT-54932[this issue], you cannot consider that the mocks have been initialized in yout `@BeforeTest` methods. | ||
You can override `initMocksBeforeTest` if you need to initialize your mocks before each test: | ||
[source,kotlin] | ||
---- | ||
class MyTests : TestsWithMocks() { | ||
override fun initMocksBeforeTest() { | ||
// Access all injected values: | ||
// mocks, fakes & withMocks properties | ||
} | ||
} | ||
---- | ||
==== | ||
|
||
In case your test class already extends another class, you can use the `ITestsWithMocks` interface instead: | ||
|
||
[source,kotlin] | ||
---- | ||
@UsesFakes(User::class) | ||
class MyTests : MySuperAbstractTests(), ITestsWithMocks { //<1> | ||
override val mocksState = ITestsWithMocks.State() //<2> | ||
override fun setUpMocks() = injectMocks(mocker) | ||
// ...your tests... | ||
} | ||
---- | ||
<1> The class implements the `ITestsWithMocks` interface, which provides all helper methods. | ||
<2> The class needs to provide an `ITestsWithMocks.State` (since the interface cannot provide one). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
= Injecting your test classes | ||
|
||
Instead of manually creating your own mocks & fakes, it can be useful to inject them in your test class, especially if you have multiple tests using them. | ||
|
||
[source,kotlin] | ||
---- | ||
@UsesFakes(User::class) | ||
class MyTests { | ||
@Mock lateinit var db: Database | ||
@Mock lateinit var api: API | ||
@Fake lateinit var user: User | ||
lateinit var controller: Controller | ||
val mocker = Mocker() | ||
@BeforeTest fun setUp() { | ||
mocker.reset() //<1> | ||
this.injectMocks(mocker) //<2> | ||
controller = ControllerImpl(db, api) //<3> | ||
} | ||
@Test fun controllerTest() { | ||
mocker.every { view.render(isAny()) } returns true | ||
controller.start() | ||
mocker.verify { view.render(model) } | ||
} | ||
} | ||
---- | ||
<1> Resets the mocker before any test (which removes all mocked behaviour & logged calls), so that each test gets a "clean" mocker. | ||
<2> Injects mocks and fakes. | ||
<3> Create classes to be tested with injected mocks & fakes. | ||
|
||
As soon as a class `T` contains a `@Mock` or `@Fake` annotated property, a `T.injectMocks(Mocker)` function will be created by the processor. | ||
|
||
IMPORTANT: Don't forget to `reset` the `Mocker` in a `@BeforeTest` method! |
Oops, something went wrong.