├── content ├── docs │ ├── tips │ │ ├── chains.md │ │ ├── exclude.md │ │ ├── timeout.md │ │ ├── _index.md │ │ └── unit.md │ ├── getting-started │ │ ├── _index.md │ │ ├── why-mockk.md │ │ └── why-mocking.md │ ├── mocking │ │ ├── clear.md │ │ ├── hierarchies.md │ │ ├── _index.md │ │ ├── spy.md │ │ ├── constructor.md │ │ ├── coroutines.md │ │ ├── relax.md │ │ ├── extension.md │ │ ├── stubbing.md │ │ ├── annotation.md │ │ ├── static.md │ │ ├── answers.md │ │ └── verify.md │ ├── matching │ │ ├── any.md │ │ ├── combine.md │ │ ├── oftype.md │ │ ├── equal.md │ │ ├── vararg.md │ │ ├── capture.md │ │ ├── _index.md │ │ ├── custom.md │ │ ├── compareto.md │ │ └── with.md │ ├── mockito-migrate │ │ ├── _index.md │ │ ├── eq.md │ │ ├── any.md │ │ ├── arg-that.md │ │ ├── void.md │ │ ├── create-mock.md │ │ ├── argument-captor.md │ │ ├── verify.md │ │ └── when.md │ ├── quick │ │ └── android.md │ └── method-index.md ├── _index.md └── menu │ └── index.md ├── .github ├── FUNDING.yml └── workflows │ └── main.yml ├── .gitignore ├── static ├── google318c7fae2befe621.html ├── favicon.png ├── cover │ ├── mockk-bike-iso.png │ ├── mockk-bike.afdesign │ ├── mockk-bike-iso.afdesign │ └── mockk-bike-iso-transparent.svg └── favicon.svg ├── assets ├── _variables.scss ├── keys.js ├── ads.js └── _custom.scss ├── .gitmodules ├── book.json ├── layouts ├── partials │ └── docs │ │ ├── html-head-title.html │ │ ├── inject │ │ ├── content-before.html │ │ ├── toc-after.html │ │ ├── footer.html │ │ ├── head.html │ │ └── menu-before.html │ │ ├── parent-title.html │ │ ├── header.html │ │ └── html-head.html └── _default │ └── baseof.html ├── package.json ├── resources └── _gen │ └── assets │ └── scss │ ├── book.scss_50fc8c04e12a2f59027287995557ceff.json │ ├── mockk-guidebook │ ├── book.scss_50fc8c04e12a2f59027287995557ceff.json │ └── book.scss_50fc8c04e12a2f59027287995557ceff.content │ └── book.scss_50fc8c04e12a2f59027287995557ceff.content ├── config.yaml └── README.md /content/docs/tips/chains.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /content/docs/tips/exclude.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: notwoods 2 | -------------------------------------------------------------------------------- /content/docs/tips/timeout.md: -------------------------------------------------------------------------------- 1 | # Timeouts 2 | -------------------------------------------------------------------------------- /content/docs/getting-started/_index.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | {{
}} 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | _book 3 | public/ 4 | .DS_Store 5 | .hugo_build.lock 6 | -------------------------------------------------------------------------------- /static/google318c7fae2befe621.html: -------------------------------------------------------------------------------- 1 | google-site-verification: google318c7fae2befe621.html -------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NotWoods/mockk-guidebook/HEAD/static/favicon.png -------------------------------------------------------------------------------- /assets/_variables.scss: -------------------------------------------------------------------------------- 1 | /* You can override SASS variables here. */ 2 | 3 | $body-min-width: 0; 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "themes/book"] 2 | path = themes/book 3 | url = https://github.com/alex-shpak/hugo-book 4 | -------------------------------------------------------------------------------- /static/cover/mockk-bike-iso.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NotWoods/mockk-guidebook/HEAD/static/cover/mockk-bike-iso.png -------------------------------------------------------------------------------- /static/cover/mockk-bike.afdesign: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NotWoods/mockk-guidebook/HEAD/static/cover/mockk-bike.afdesign -------------------------------------------------------------------------------- /static/cover/mockk-bike-iso.afdesign: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NotWoods/mockk-guidebook/HEAD/static/cover/mockk-bike-iso.afdesign -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "MockK Guidebook", 3 | "description": "A guide to using the MockK testing library.", 4 | "author": "Tiger Oakes" 5 | } 6 | -------------------------------------------------------------------------------- /layouts/partials/docs/html-head-title.html: -------------------------------------------------------------------------------- 1 | {{ partial "docs/title" . }}{{ partial "docs/parent-title" . }}{{ if not .IsHome }} | {{ .Site.Title -}}{{ end }} 2 | -------------------------------------------------------------------------------- /content/docs/mocking/clear.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Clear state 3 | summary: > 4 | (TODO) Clearing the state of a mock. 5 | weight: 90 6 | --- 7 | 8 | # Clear state 9 | -------------------------------------------------------------------------------- /content/docs/mocking/hierarchies.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Chain mocks into hierarchies 3 | summary: > 4 | (TODO) Building a mock with less code using lambdas. 5 | weight: 110 6 | --- 7 | -------------------------------------------------------------------------------- /layouts/partials/docs/inject/content-before.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /layouts/partials/docs/inject/toc-after.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /content/docs/matching/any.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Allow any argument 3 | summary: > 4 | (TODO) `any`thing goes here. 5 | weight: 20 6 | --- 7 | 8 | # Allowing any argument 9 | - `any` 10 | - `allAny` 11 | -------------------------------------------------------------------------------- /content/docs/matching/combine.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Combine matchers 3 | summary: > 4 | (TODO) Logical operators `and`, `or`, `not` for matchers. 5 | weight: 90 6 | --- 7 | 8 | # Combining matchers 9 | - `and` 10 | - `or` 11 | - `not` 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mockk-guidebook", 3 | "private": true, 4 | "dependencies": { 5 | "gitbook-cli": "^2.3.2" 6 | }, 7 | "scripts": { 8 | "build": "gitbook build", 9 | "start": "gitbook serve" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /layouts/partials/docs/parent-title.html: -------------------------------------------------------------------------------- 1 | {{ $title := "" }} 2 | 3 | {{ with .Parent }} 4 | {{ if and (ne .Title "Docs") (ne .Title "") }} 5 | {{ $title = (printf " | %s" .Title) }} 6 | {{ end }} 7 | {{ end }} 8 | 9 | {{ return $title }} 10 | -------------------------------------------------------------------------------- /resources/_gen/assets/scss/book.scss_50fc8c04e12a2f59027287995557ceff.json: -------------------------------------------------------------------------------- 1 | {"Target":"book.min.66a7ae0ec09df2dfc58bfb0d30143af7a784be481cd37bc1e244295eb417133f.css","MediaType":"text/css","Data":{"Integrity":"sha256-ZqeuDsCd8t/Fi/sNMBQ696eEvkgc03vB4kQpXrQXEz8="}} -------------------------------------------------------------------------------- /resources/_gen/assets/scss/mockk-guidebook/book.scss_50fc8c04e12a2f59027287995557ceff.json: -------------------------------------------------------------------------------- 1 | {"Target":"book.min.505232ebde932d285c6eb8581ce87cd900df6de172f7e5bbfb66679414b45435.css","MediaType":"text/css","Data":{"Integrity":"sha256-UFIy696TLShcbrhYHOh82QDfbeFy9+W7+2ZnlBS0VDU="}} -------------------------------------------------------------------------------- /content/docs/matching/oftype.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Argument of a certain type 3 | summary: > 4 | (TODO) Don't allow anyone, just arguments that are `ofType`. 5 | weight: 30 6 | methods: 7 | - ofType 8 | --- 9 | 10 | # Argument of a certain type 11 | 12 | - `ofType` 13 | -------------------------------------------------------------------------------- /content/docs/matching/equal.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Check equality 3 | summary: > 4 | (TODO) Checking if an argument is equal using `eq`, `refEq`, `isNull`, and more. 5 | weight: 10 6 | --- 7 | 8 | # Checking equality 9 | - `eq`/`neq` 10 | - `isNull` 11 | - `refEq`/`nrefEq` 12 | -------------------------------------------------------------------------------- /content/docs/matching/vararg.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Variable arguments 3 | summary: > 4 | (TODO) Matching variable arguments with `anyVararg` and more. 5 | weight: 70 6 | --- 7 | 8 | # Variable arguments 9 | - `anyVararg` 10 | - `varargAny` 11 | - `varargAll` 12 | - `any...Vararg` 13 | - `varargAny...` 14 | - `varargAll...` 15 | -------------------------------------------------------------------------------- /content/docs/mockito-migrate/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Migrating from Mockito 3 | summary: > 4 | Learn how to use MockK by seeing equivalents to functions in Mockito. 5 | --- 6 | 7 | # Migrating from Mockito 8 | 9 | Learn how to use MockK by seeing equivalents to functions in [Mockito](https://site.mockito.org/). 10 | 11 | {{
}} 12 | -------------------------------------------------------------------------------- /layouts/partials/docs/inject/footer.html: -------------------------------------------------------------------------------- 1 | 2 | Buy Me a Coffee at ko-fi.com 10 | 11 | -------------------------------------------------------------------------------- /content/docs/tips/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Tips 3 | summary: > 4 | In this section we present a number of tips that we have collected over the course of using MockK in the real world. 5 | --- 6 | 7 | # Tips 8 | 9 | In this section we present a number of tips that we have collected over the course of using MockK in the real world. 10 | 11 | {{
}} 12 | -------------------------------------------------------------------------------- /content/docs/matching/capture.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Capture arguments to check later 3 | summary: > 4 | (TODO) `capture` arguments out of stubs and verify calls into a `slot`. 5 | weight: 60 6 | --- 7 | 8 | # Capturing arguments to check later 9 | - `capture` 10 | - `captureNullable` 11 | - `captureLambda` 12 | - `captureCoroutine` 13 | - `invoke`/`coInvoke` (maybe?) 14 | -------------------------------------------------------------------------------- /content/docs/getting-started/why-mockk.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Why MockK? 3 | summary: "(TODO) About the MockK framework." 4 | weight: 20 5 | --- 6 | 7 | # Why MockK 8 | 9 | MockK is a mocking framework built in Kotlin to be used with Kotlin programs. Because MockK is written in Kotlin, it has first-class support for Kotlin language features such as singleton objects, extension functions, and final classes. 10 | -------------------------------------------------------------------------------- /content/docs/mocking/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Mocking 3 | summary: > 4 | Mocking start with one call, the `mockk` function. 5 | --- 6 | 7 | # Mocking 8 | 9 | Mocking start with one call, the `mockk` function. This function takes in a class and returns a fake version of it, where all functions are present but will throw when called. 10 | 11 | ```kotlin 12 | import io.mockk.mockk 13 | 14 | val mockedFile = mockk() 15 | ``` 16 | 17 | {{
}} 18 | -------------------------------------------------------------------------------- /layouts/partials/docs/header.html: -------------------------------------------------------------------------------- 1 |
2 | 5 | 6 | 11 |
12 | -------------------------------------------------------------------------------- /content/docs/matching/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Argument matching 3 | summary: > 4 | Argument matchers are placeholders use to specify what values can be used in a function. They can be used with stubs and verification. 5 | --- 6 | 7 | # Argument matching 8 | 9 | Argument matchers are placeholders use to specify what values can be used in a function. They can be used with [stubs](../mocking/stubbing.md) and [verification](../mocking/verify.md). 10 | 11 | {{
}} 12 | -------------------------------------------------------------------------------- /assets/keys.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | /** @type {Map} */ 4 | const accessKeys = new Map(); 5 | /** @type {NodeListOf} */ 6 | const focusable = document.querySelectorAll('input[accesskey]'); 7 | focusable.forEach((input) => { 8 | accessKeys.set(input.accessKey, input); 9 | }); 10 | 11 | document.addEventListener('keydown', (evt) => { 12 | if (evt.repeat) return; // Ignore holding down keys 13 | const input = accessKeys.get(evt.key); 14 | 15 | if (input) { 16 | evt.preventDefault(); 17 | input.click(); 18 | } 19 | }); 20 | -------------------------------------------------------------------------------- /content/docs/tips/unit.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Return `Unit` 3 | --- 4 | 5 | # Return `Unit` 6 | 7 | When [stubbing](../mocking/stubbing.md) a function that returns nothing, MockK provides a few shortcuts. 8 | 9 | ```kotlin 10 | val logger = mockk() 11 | 12 | every { logger.log(any()) } returns Unit 13 | every { logger.log(any()) } answers { Unit } 14 | every { logger.log(any()) } just Runs 15 | justRun { logger.log(any()) } 16 | ``` 17 | 18 | `just Runs` is the nicest to use, since its shorter than `returns` and `answers` and additionally works with `coEvery`. 19 | 20 | ```kotlin 21 | coEvery { logger.log(any()) } just Runs 22 | ``` 23 | -------------------------------------------------------------------------------- /content/docs/mocking/spy.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Spy on existing classes 3 | summary: > 4 | Using `spyk` to mix mocks and real classes. 5 | weight: 40 6 | --- 7 | 8 | # Spy on existing classes 9 | 10 | Rather than mocking an object, you can create spies of real objects. Spies will run the real methods in a class, unlike mocks which don't run anything. Stubbing methods on a spy will run the stub instead, so you can have a mixture of real methods and stubbed methods. 11 | 12 | Spies get their name because you can spy on the code you're testing and see what methods it called. Spies let you [verify that a method is called](./verify.md), just like a mock. 13 | -------------------------------------------------------------------------------- /assets/ads.js: -------------------------------------------------------------------------------- 1 | const mobileBreakpoint = '56rem'; // $mobile-breakpoint 2 | 3 | const invisibleAdId = window.matchMedia(`(max-width: ${mobileBreakpoint})`).matches 4 | ? 'toc-sidebar-ad' 5 | : 'content-ad' 6 | document.getElementById(invisibleAdId).remove(); 7 | ethicalads.load(); 8 | 9 | if (document.monetization) { 10 | document.monetization.addEventListener('monetizationstart', () => { 11 | if (document.monetization.state === 'started') { 12 | console.log('Payment started, hiding ads'); 13 | document.querySelectorAll('[data-ea-publisher]').forEach((el) => { 14 | el.hidden = true; 15 | }); 16 | } 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /content/docs/mockito-migrate/eq.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "`eq`" 3 | summary: > 4 | Mockito's `eq`, `refEq`, and `same` argument matchers. 5 | weight: 20 6 | --- 7 | 8 | # `eq` 9 | 10 | By default, Mockito verifies argument values by using the `equals()` method, which corresponds to `==` in Kotlin. 11 | 12 | ```kotlin 13 | verify(mock.containsAll(listOf("a", "b"), true)) 14 | ``` 15 | 16 | However, once argument matchers like `any()` are used, then the `eq` argument matcher must be used for literal values. 17 | 18 | ```kotlin 19 | verify(mock.containsAll(eq(listOf("a", "b")), anyBoolean())) 20 | ``` 21 | 22 | In MockK, `eq` is always used as the default argument matcher. You can mix literal values with `any` without issue. 23 | 24 | ```kotlin 25 | verify { mock.containsAll(listOf("a", "b", any())) } 26 | ``` 27 | 28 | TODO: 29 | - `refEq` 30 | - `same` 31 | -------------------------------------------------------------------------------- /content/docs/mockito-migrate/any.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "`any*`" 3 | summary: > 4 | The "any" family of matchers: `any`, `anyBoolean`, `anyByte`, `anyChar`, `anyDouble`, `anyFloat`, `anyInt`, `anyLong`, `anyObject`, `anyShort`, and `anyString`. 5 | weight: 30 6 | --- 7 | 8 | # `any*` 9 | 10 | When creating a stub or verifying a call, Mockito provides many different argument matchers. Besides `eq`, the most commonly used are the "any" family: `any`, `anyBoolean`, `anyByte`, `anyChar`, `anyDouble`, `anyFloat`, `anyInt`, `anyLong`, `anyObject`, `anyShort`, and `anyString`. In MockK, these variations are all replaced by a single `any` matcher. 11 | 12 | ```kotlin 13 | // TODO example class that takes object, int, string parameters. Show stub & verify for both libs. 14 | ``` 15 | 16 | If you want to check for any null value, or any not-null value, the `isNull` matcher can be used. 17 | 18 | TODO: `isNull()`, `isNull(inverse = true)` 19 | 20 | TODO: `ofType` 21 | -------------------------------------------------------------------------------- /content/docs/mockito-migrate/arg-that.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "`argThat`" 3 | summary: > 4 | Porting custom matchers with `argThat` 5 | weight: 50 6 | --- 7 | 8 | # `argThat` 9 | 10 | The `argThat` argument matcher in Mockito lets you create advanced argument matchers that run a function on passed arguments, and checks if the function returns `true`. 11 | 12 | If you have a complicated class that can't be easily checked using `.equals()`, a custom matcher can be a useful tool. 13 | 14 | ```kotlin 15 | `when`( 16 | mockedCar.drive(argThat { engine -> engine.dieselEngine }) 17 | ).thenReturn(true) 18 | ``` 19 | 20 | MockK has a similar [argument matcher called `match`](../matching/custom.md). Just like `argThat`, you can pass a lambda in that returns a boolean. 21 | 22 | ```kotlin 23 | every { 24 | mockedCar.drive(match { engine -> engine.dieselEngine }) 25 | } returns true 26 | ``` 27 | 28 | MockK also lets you use coroutines with `match`. Just replace the function with `coMatch`, then pass a suspend function lambda in. See [Coroutines and suspend functions](../mocking/coroutines.md) for more details. 29 | -------------------------------------------------------------------------------- /content/docs/mockito-migrate/void.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "`void` methods" 3 | summary: > 4 | MockK makes it easier to mock methods that return `void`. 5 | weight: 70 6 | --- 7 | 8 | # `void` methods 9 | 10 | Mockito's `when` method doesn't work with `void` methods. To create a stub that doesn't return anything, the `doNothing` method is used. 11 | 12 | ```kotlin 13 | val mockedFile = mock(File::class.java) 14 | 15 | doNothing().`when`(mockedFile).write(any()) 16 | ``` 17 | 18 | MockK doesn't have any restrictions with these methods, as they [return `Unit` in Kotlin](https://kotlinlang.org/docs/reference/java-interop.html#methods-returning-void). As a result, the standard `returns` infix function can be used. 19 | 20 | ```kotlin 21 | val mockedFile = mockk() 22 | 23 | every { mockedFile.write(any()) } returns Unit 24 | ``` 25 | 26 | MockK also provides the `justRun` method as a shorthand for `every { x } returns Unit`. For more information, see the [Returning `Unit` tip](../tips/unit.md). 27 | 28 | ```kotlin 29 | val mockedFile = mockk() 30 | 31 | justRun { mockedFile.write(any()) } 32 | ``` 33 | -------------------------------------------------------------------------------- /content/docs/matching/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Custom matching functions 3 | summary: > 4 | (TODO) Adding additional matchers with the `match` function. 5 | weight: 50 6 | methods: 7 | - match 8 | - coMatch 9 | - matchNullable 10 | - coMatchNullable 11 | --- 12 | 13 | # Custom matching functions 14 | 15 | When built-in argument matchers aren't sufficient, custom matchers can be written. A custom argument matcher simply needs to take in the argument as a parameter and return `true` if it matches, and `false` if it does not. This custom boolean function can then be passed to the special `match` function. 16 | 17 | ```kotlin 18 | every { 19 | mockedCar.drive(match { engine -> 20 | engine.type === "Diesel" 21 | }) 22 | } returns true 23 | ``` 24 | 25 | If the argument is nullable, a variant called `matchNullable` can be used instead. 26 | 27 | ```kotlin 28 | every { 29 | mockedCar.drive(matchNullable { engine -> 30 | engine != null && engine.type === "Diesel" 31 | }) 32 | } returns true 33 | ``` 34 | 35 | ## `Matcher` subclass 36 | 37 | TODO extend `Matcher` 38 | 39 | ## Inline extension function helper 40 | 41 | TODO `MockKMatcherScope` extension function 42 | -------------------------------------------------------------------------------- /content/docs/matching/compareto.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Comparables 3 | summary: > 4 | Matching smaller numbers, bigger numbers, and `more`. 5 | weight: 80 6 | --- 7 | 8 | # Comparables 9 | 10 | - `less` 11 | - `more` 12 | - `range` 13 | - `cmpEq` 14 | 15 | MockK provides a few argument matchers for numbers and comparable objects. These matches all use the `compareTo` function to compare objects. 16 | 17 | ## `more` 18 | 19 | Checks if the argument is more than the value given to the matcher. Valid arguments will return a negative number when compared to the matcher value. 20 | 21 | ```kotlin 22 | assertTrue(value.compareTo(arg) < 0) 23 | ``` 24 | 25 | ## `less` 26 | 27 | Checks if the argument is less than the value given to the matcher. Valid arguments will return a positive number when compared to the matcher value. 28 | 29 | ```kotlin 30 | assertTrue(value.compareTo(arg) > 0) 31 | ``` 32 | 33 | ## `cmpEq` 34 | 35 | Checks if the argument is equal to the value given to the matcher, according to the `compareTo` function. Valid arguments will return 0 when compared to the matcher value. 36 | 37 | ```kotlin 38 | assertTrue(value.compareTo(arg) == 0) 39 | ``` 40 | 41 | ## `range` 42 | 43 | TODO 44 | -------------------------------------------------------------------------------- /content/docs/mocking/constructor.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Mock constructors in code you don't own 3 | summary: > 4 | Advanced mocking with `mockkConstructor`. 5 | weight: 60 6 | --- 7 | 8 | # Mock constructors in code you don't own 9 | 10 | Sometimes your classes have dependencies that they construct themselves. While it's best to use a system like dependency injection to avoid this, MockK makes it possible to control constructors and make them return a mocked instance. 11 | 12 | The `mockkConstructor(T::class)` function takes in a class reference. Once used, every constructor of that type will start returning a singleton that can be mocked. Rather than building a new instance every time the constructor is called, MockK generates a singleton and always returns the same instance. This will apply to all constructors for a given class, there is no way to distinguish between them. 13 | 14 | The mocked result can be obtained by using `anyConstructed()`. Using this function, stubbing and verification can be done just like any other mock. 15 | 16 | ## Unmocking 17 | 18 | If you'd like to revert back to the real constructor, you can use the `unmockkConstructor` method. This removes any stubbed behaviour you may have added. 19 | -------------------------------------------------------------------------------- /assets/_custom.scss: -------------------------------------------------------------------------------- 1 | /* You can add custom styles here. */ 2 | 3 | a del { 4 | opacity: 0.5; 5 | } 6 | 7 | .kofi { 8 | display: block; 9 | text-align: center; 10 | margin-top: 1rem; 11 | } 12 | 13 | .author { 14 | display: block; 15 | margin-bottom: 2rem; 16 | } 17 | .logo-icon { 18 | transition: opacity 0.3s linear; 19 | } 20 | .logo-icon--color, 21 | .author:hover .logo-icon--monochrome { 22 | opacity: 0; 23 | } 24 | .author:hover .logo-icon--color { 25 | opacity: 1; 26 | } 27 | .text-over path { 28 | stroke-dasharray: 25; 29 | stroke-dashoffset: 0; 30 | transition: stroke-dashoffset 0.5s linear; 31 | } 32 | .author:hover .text-over path { 33 | stroke-dashoffset: 25; 34 | } 35 | 36 | .book-menu nav { 37 | max-width: calc(100vw - 2rem); 38 | } 39 | 40 | .book-toc .book-toc-inner nav { 41 | width: auto; 42 | padding: 0; 43 | position: static; 44 | overflow-x: unset; 45 | overflow-y: unset; 46 | } 47 | .book-toc-inner { 48 | width: $toc-width; 49 | padding: $padding-16; 50 | 51 | @include fixed; 52 | } 53 | @media screen and (min-width: $container-max-width) { 54 | .book-toc .book-toc-inner nav { 55 | padding: 0; 56 | } 57 | .book-toc-inner { 58 | padding: $padding-16 * 2 $padding-16; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /content/docs/mocking/coroutines.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Coroutines and suspend functions 3 | summary: > 4 | Using `coEvery`, `coVerify`, and more to mock coroutines. 5 | weight: 50 6 | --- 7 | 8 | # Coroutines and suspend functions 9 | 10 | As MockK uses function literals to create stubs, small changes are needed to stub suspend functions. MockK provides functions prefixed with `co` as equivalents to other functions, such as `coEvery` and `coAnswers`. 11 | 12 | ```kotlin 13 | val mockedFile = mockk() 14 | 15 | coEvery { mockedFile.readAsync() } returns "hello world" 16 | coEvery { mockedFile.writeAsync(any()) } coAnswers { call -> 17 | doAsyncWork() 18 | Unit 19 | } 20 | ``` 21 | 22 | The full list of methods with coroutine equivalents is: 23 | 24 | - [`coEvery`](./stubbing.md) 25 | - [`coJustRun`](../tips/unit.md) 26 | - [`coVerify`](./verify.md) 27 | - [`coVerifyAll`](./verify.md) 28 | - [`coVerifyOrder`](./verify.md) 29 | - [`coVerifySequence`](./verify.md) 30 | - [`coExcludeRecords`](../tips/exclude.md) 31 | - [`coMatch`](../matching/custom.md) 32 | - [`coMatchNullable`](../matching/custom.md) 33 | - [`coWithArg`](../matching/with.md) 34 | - [`coWithNullableArg`](../matching/with.md) 35 | - [`coAnswers`](./stubbing.md) 36 | - `coAndThen` 37 | - `coInvoke` 38 | -------------------------------------------------------------------------------- /content/docs/quick/android.md: -------------------------------------------------------------------------------- 1 | # Android Quickstart 2 | 3 | MockK works great with Android and allows you to mock objects in both your Android unit tests and instrumented tests. MockK can handle mocking `Context`, static functions, and more to help you test your Android code. 4 | 5 | To install MockK, all you need to do is add it as a dependency in your module's Gradle file. In most Android Studio projects, this file is located at _app/build.gradle_. Once you open the file, search for the `dependencies` block and add a new line. 6 | 7 | ```groovy 8 | dependencies { 9 | ... 10 | testImplementation "io.mockk:mockk:$mockk_version" 11 | } 12 | ``` 13 | 14 | `$mockk_version` should be replaced with the version of MockK you wish to use. [The latest version is listed on the Maven website](https://search.maven.org/artifact/io.mockk/mockk). 15 | 16 | After syncing your project with Gradle files, MockK will be available for use in your unit tests (located in _app/src/test_). To use MockK in your instrumented tests (located in _app/src/androidTest_), an additional line is needed in your module's Gradle file. 17 | 18 | ```groovy 19 | dependencies { 20 | ... 21 | androidTestImplementation "io.mockk:mockk-android:$mockk_version" 22 | } 23 | ``` 24 | 25 | Unlike unit tests, instrumented tests are run live on an Android device or emulator. 26 | 27 | TODO add differences between versions 28 | -------------------------------------------------------------------------------- /layouts/partials/docs/inject/head.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 10 | 14 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 39 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: Deploy 4 | 5 | # Controls when the action will run. Triggers the workflow on push or pull request 6 | # events but only for the master branch 7 | on: 8 | push: 9 | branches: 10 | - main 11 | pull_request: 12 | 13 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 14 | jobs: 15 | # This workflow contains a single job called "build" 16 | build: 17 | # The type of runner that the job will run on 18 | runs-on: ubuntu-latest 19 | 20 | # Steps represent a sequence of tasks that will be executed as part of the job 21 | steps: 22 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 23 | - name: Checkout Repo 24 | uses: actions/checkout@v3 25 | with: 26 | submodules: true 27 | 28 | - name: Setup Hugo 29 | uses: peaceiris/actions-hugo@v2 30 | with: 31 | hugo-version: "0.100.1" 32 | extended: true 33 | 34 | - name: Build 35 | run: hugo --minify --gc --cleanDestinationDir 36 | 37 | - name: Publish Site 38 | uses: peaceiris/actions-gh-pages@v3 39 | if: ${{ github.ref == 'refs/heads/main' }} 40 | with: 41 | github_token: ${{ secrets.GITHUB_TOKEN }} 42 | publish_dir: ./public 43 | -------------------------------------------------------------------------------- /content/docs/mocking/relax.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Automatically stub by relaxing 3 | summary: > 4 | How to change the default `mockk` result with `relaxed`. 5 | weight: 30 6 | --- 7 | 8 | # Automatically stub by relaxing 9 | 10 | If a method has not been stubbed, MockK will throw an error if it is called. This is designed to help make your tests easier to debug, as you'll know if you forgot to mock a method. 11 | 12 | ```kotlin 13 | interface Navigator { 14 | val currentLocation: String 15 | 16 | fun navigateTo(newLocation: String): Unit 17 | } 18 | 19 | val navigator = mockk() 20 | every { navigator.currentLocation } returns "Home" 21 | 22 | // prints "Home" 23 | println(navigator.currentLocation) 24 | // throws an error 25 | navigator.navigateTo("Store") 26 | ``` 27 | 28 | For more complicated objects, you can tell MockK to return simple values for all methods that have not been stubbed, rather than throwing. This is done by using the `relaxed` parameter when calling the `mockk` function. 29 | 30 | ```kotlin 31 | val navigator = mockk(relaxed = true) 32 | every { navigator.currentLocation } returns "Home" 33 | 34 | // prints "Home" 35 | println(navigator.currentLocation) 36 | // does nothing 37 | navigator.navigateTo("Store") 38 | ``` 39 | 40 | If desired, you can choose to only relax methods that return `Unit`. This lets you pre-stub methods that just trigger side-effects rather than returning a value. 41 | 42 | ```kotlin 43 | val navigator = mockk(relaxUnitFun = true) 44 | ``` 45 | -------------------------------------------------------------------------------- /content/docs/mocking/extension.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Mock top-level and extension functions 3 | summary: > 4 | Mocking top-level functions with `mockkStatic`. 5 | weight: 80 6 | --- 7 | 8 | # Mock top-level and extension functions 9 | 10 | ## Top-level functions 11 | 12 | Kotlin lets you write functions that don't belong to any class or object, called [top-level functions](https://kotlinlang.org/docs/reference/functions.html#function-scope). These calls are translated to static methods in Java, and a special Java class is generated to hold the functions. These top-level functions can be mocked using [`mockkStatic`](./static.md). You just need to import the function and pass a reference as the argument. 13 | 14 | ```kotlin 15 | import pkg.toplevelFunction 16 | 17 | mockkStatic(::toplevelFunction) 18 | every { toplevelFunction() } returns "top" 19 | ``` 20 | 21 | ## Extension functions 22 | 23 | Depending on where an extension function is located, it may correspond to a top-level function or a class member. If placed inside a class, the extension function is attached to that class and can be mocked using the `with` method. 24 | 25 | ```kotlin 26 | // TODO val mock = ... 27 | 28 | with (mock) { 29 | every { any().extensionFunction() } returns "result" 30 | } 31 | ``` 32 | 33 | If the extension function is inside an object, the code is similar but the object needs to be mocked first. 34 | 35 | When the extension function is in the top-level of a file, it can be mocked like other top-level functions using `mockkStatic`. 36 | -------------------------------------------------------------------------------- /content/docs/mockito-migrate/create-mock.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Create a mock 3 | summary: > 4 | The similarities and differences in creating mocks between Mockito and MockK. 5 | weight: 1 6 | --- 7 | 8 | # Create a mock 9 | 10 | The syntax to create a mock is very similar in Mockito and MockK. However, the behaviour is slightly different. 11 | 12 | ```kotlin 13 | // Mockito 14 | val mockedFile = mock(File::class.java) 15 | 16 | mockedFile.read() // does nothing 17 | ``` 18 | 19 | ```kotlin 20 | // MockK 21 | val mockedFile = mockk() 22 | 23 | mockedFile.read() // throws because the method was not stubbed 24 | ``` 25 | 26 | Mocked objects in MockK resemble Mockito's [`STRICT_STUBS`](https://javadoc.io/static/org.mockito/mockito-core/3.3.3/org/mockito/quality/Strictness.html#STRICT_STUBS) mode by default. If a method is not stubbed, then it will throw. This makes it easier to catch methods that are being called when you do not expect it, or when methods are being called with different arguments. 27 | 28 | Mockito's default lenient behaviour can be replicated with the `relaxed` setting. Relaxed mocks will have default stubs for all methods. 29 | 30 | ```kotlin 31 | // MockK 32 | val mockedFile = mockk(relaxed = true) 33 | 34 | mockedFile.read() // will not throw 35 | ``` 36 | 37 | If desired, you can choose to only relax methods that return `Unit`. 38 | 39 | ```kotlin 40 | // MockK 41 | val mockedFile = mockk(relaxUnitFun = true) 42 | 43 | mockedFile.read() // returns Unit, will not throw 44 | mockedFile.exists() // throws as the method returns Boolean 45 | ``` 46 | -------------------------------------------------------------------------------- /content/docs/getting-started/why-mocking.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Why use mocks 3 | summary: "I thought lying was bad!" 4 | weight: 10 5 | --- 6 | 7 | # Why use mocks 8 | 9 | How do you make sure your code runs like it's supposed to? You can start out building your app, playing around with it, and trying buttons while ensuring there are no crashes. However, as your codebase grows, testing every edge case for every function becomes more difficult to do manually. Enter automated testing: code that runs your app with pre-written instructions then checks that the result matches your expectation. 10 | 11 | Most automated tests are unit tests: tests that check a single function at a time, rather than the entire app. "Units" refer to parts of your code that can be tested in isolation. This may be a standalone function or a single class. 12 | 13 | However, classes usually depend on other classes to run properly. A `Car` class may depend on an `Engine` class. You need to provide these dependencies for the `Car` to work, but it's hard to write tests in isolation if you're also configuring the `Engine` at the same time. 14 | 15 | You can work around this problem by creating fake versions of the dependencies. These fake classes are called "mocks". You can configure mocks in many different ways to be suitable for a variety of unit tests. They can [throw an error if the tested class calls unexpected methods on the mock](../mocking/stubbing.md), or [allow any methods to be called and automatically provide fake results](../mocking/relax.md). You have fine control over the behaviour of every method on a mock, so your test can handle all the possible edge cases. 16 | 17 | Writing unit tests will help you track down bugs ahead of time, and ensure they don't reappear when you make changes to your code. Mocks are an important tool in your unit testing toolkit to help you write isolated tests. Read on to learn how to use [the MockK mocking framework](../mocking/_index.md), or learn [why you should use MockK over other frameworks](./why-mockk.md). 18 | -------------------------------------------------------------------------------- /content/docs/mockito-migrate/argument-captor.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "`ArgumentCaptor`" 3 | summary: > 4 | Capturing arguments to check them later. 5 | weight: 60 6 | --- 7 | 8 | # `ArgumentCaptor` 9 | 10 | When you need to run additional assertions on an argument, the `ArgumentCaptor` is the tool for the job in Mockito. An `ArgumentCaptor` will keep track of arguments passed to a mocked method, then allow you to retreve the argument later. 11 | 12 | ```kotlin 13 | val personArgument = ArgumentCaptor.forClass(Person::class.java) 14 | 15 | verify(mockPhone).call(personArgument.capture()) 16 | 17 | assertEquals("Sarah Jane", personArgument.value.name) 18 | ``` 19 | 20 | MockK has a similar [utility called a `CapturingSlot`](../matching/capture.md). The functionality is very similar to Mockito, but the usage is different. Rather than calling the method `argumentCaptor.capture()` to create a argument matcher, you wrap the slot in a `capture()` function. You access the captured value using the `slot.captured` property rather than the `argumentCaptor.value` getter. 21 | 22 | ```kotlin 23 | val personSlot = slot() 24 | 25 | every { mockPhone.call(capture(personSlot)) } returns Unit 26 | //or justRun { mockPhone.call(capture(personSlot)) } 27 | 28 | assertEquals("Sarah Jane", personSlot.captured.name) 29 | ``` 30 | 31 | As an alternative to `CapturingSlot`, a `MutableList` can be used to store captured arguments. Simply pass an instance of a mutable list to `capture` instead of the slot. This allows you to record all captured values, as `CapturingSlot` only records the most recent value. 32 | 33 | ## Inline assertions 34 | 35 | It turns out that there is an even simpler way to run assertions on an argument in MockK. The [`withArg` function](../matching/with.md) is an argument matcher that takes a lambda that will be executed when the mocked function is called, with the argument passed to the lambda. This allows you to run assertions without managing argument captors or capturing slots. 36 | 37 | ```kotlin 38 | every { 39 | mockPhone.call(withArg { person -> 40 | assertEquals("Sarah Jane", person.name) 41 | }) 42 | } returns Unit 43 | ``` 44 | 45 | When dealing with one-off assertions, `withArg` will do everything you need with less code. 46 | -------------------------------------------------------------------------------- /content/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: MockK Guidebook, the upcoming all-in-one guide for the Kotlin mocking library 3 | type: docs 4 | aliases: 5 | - /docs/index.html 6 | summary: > 7 | A guide to using the MockK testing library. This resource is designed to help you learn how to use MockK, whether you're new to mocking or transitioning from another framework. 8 | You can skim and skip around different pages. It's a living document, so it will be receiving updates to add more information over time. 9 | --- 10 | 11 | # MockK Guidebook 12 | 13 | 14 | 15 | The upcoming all-in-one guide for the Kotlin mocking library [MockK](https://mockk.io/) in your tests. 16 | 17 | - Pages that are ~~crossed out~~ are not yet written. 18 | - Other pages are in progress. 19 | 20 | This resource is designed to help you learn how to use MockK, whether you're new to mocking or [transitioning from another framework](./docs/mockito-migrate/_index.md). You can skim and skip around different pages. It's a living document, so it will be receiving updates to add more information over time. 21 | 22 | Get started by learning about [mocking](./docs/mocking/_index.md)! 23 | 24 | --- 25 | 26 | Looking to learn more about Kotlin and Android development? I write about it on my personal blog at [tigeroakes.com](https://tigeroakes.com). Check out some of my popular articles: 27 | 28 | - [React to Jetpack Compose Dictionary](https://tigeroakes.com/posts/react-to-compose-dictionary/) 29 | - [How to easily cache Kotlin Android synthetics](https://tigeroakes.com/posts/til-kotlin-android-ext-cache/) 30 | - [Animating a strike through with Animated​Vector​Drawable and Animated​State​List​Drawable](https://medium.com/firefox-mobile-engineering/animating-a-strike-through-on-android-with-animated-vector-drawable-and-animatedstatelistdrawable-a77e66f9790f) 31 | 32 | ## Contributors 33 | 34 | Thanks to everyone who has contributed to the book! PRs are welcome on GitHub. 35 | 36 |
37 | 38 | Contributor list 39 | 40 |
41 | 42 | Made with 43 | contributors-img. 44 | 45 |
46 |
47 | -------------------------------------------------------------------------------- /content/menu/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | headless: true 3 | --- 4 | 5 | * [Getting Started](docs/getting-started/) 6 | * [Why use mocks](docs/getting-started/why-mocking.md) 7 | * [~~Why MockK~~](docs/getting-started/why-mockk.md) 8 | * [Android Quickstart](docs/quick/android.md) 9 | * [**Mocking**](docs/mocking/) 10 | * [Stub out behaviour](docs/mocking/stubbing.md) 11 | * [Verify that functions were called](docs/mocking/verify.md) 12 | * [Automatically stub by relaxing](docs/mocking/relax.md) 13 | * [Spy on existing classes](docs/mocking/spy.md) 14 | * [Coroutines and suspend functions](docs/mocking/coroutines.md) 15 | * [Mock constructors in code you don't own](docs/mocking/constructor.md) 16 | * [Mock singleton objects and static methods](docs/mocking/static.md) 17 | * [Mock top-level and extension functions](docs/mocking/extension.md) 18 | * [~~Clear state~~](docs/mocking/clear.md) 19 | * [Create many mocks quickly with annotations](docs/mocking/annotation.md) 20 | * [~~Chain mocks into hierarchies~~](docs/mocking/hierarchies.md) 21 | * [Create more complicated answers for stubs](docs/mocking/answers.md) 22 | * [**Argument matching**](docs/matching/) 23 | * [~~Check equality~~](docs/matching/equal.md) 24 | * [~~Allow any argument~~](docs/matching/any.md) 25 | * [~~Argument of a certain type~~](docs/matching/oftype.md) 26 | * [Assertions with an argument](docs/matching/with.md) 27 | * [Custom matching functions](docs/matching/custom.md) 28 | * [~~Capture arguments to check later~~](docs/matching/capture.md) 29 | * [~~Variable arguments~~](docs/matching/vararg.md) 30 | * [Comparables](docs/matching/compareto.md) 31 | * [~~Combine matchers~~](docs/matching/combine.md) 32 | * [**Migrating from Mockito**](docs/mockito-migrate/) 33 | * [Create a mock](docs/mockito-migrate/create-mock.md) 34 | * [`when` and `do*`](docs/mockito-migrate/when.md) 35 | * [`eq`](docs/mockito-migrate/eq.md) 36 | * [`any*`](docs/mockito-migrate/any.md) 37 | * [`verify`](docs/mockito-migrate/verify.md) 38 | * [`argThat`](docs/mockito-migrate/arg-that.md) 39 | * [`ArgumentCaptor`](docs/mockito-migrate/argument-captor.md) 40 | * [`void` methods](docs/mockito-migrate/void.md) 41 | * [**Tips**](docs/tips/) 42 | * [Return `Unit`](docs/tips/unit.md) 43 | * [~~Chains~~](docs/tips/chains.md) 44 | * [~~Timeouts~~](docs/tips/timeout.md) 45 | * [~~Exclude recording~~](docs/tips/exclude.md) 46 | * [Method index](docs/method-index.md) 47 | -------------------------------------------------------------------------------- /content/docs/mocking/stubbing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Stub out behaviour 3 | summary: > 4 | Using `every` and `returns` to define behaviour. 5 | weight: 10 6 | --- 7 | 8 | # Stub out behaviour 9 | 10 | Your Kotlin classes often depends on other objects and functions when running. When you are writing tests for your classes, you only want to test the class itself and not the dependency. MockK helps you create pretend versions of those dependencies instead of using the real versions. 11 | 12 | Stubbing allows you to setup canned answers when functions are called. You only need to stub methods that are called by your class, and you can ignore methods that aren't run during your test. 13 | 14 | ```kotlin 15 | interface Navigator { 16 | val currentLocation: String 17 | 18 | fun navigateTo(newLocation: String): Unit 19 | } 20 | ``` 21 | 22 | Here is an example of how to create a stub of the `Navigator` interface. 23 | 24 | ```kotlin 25 | import io.mockk.every 26 | import io.mockk.mockk 27 | 28 | val navigator = mockk() 29 | every { navigator.currentLocation } returns "Home" 30 | every { navigator.navigateTo("Park") } throws IllegalStateException("Can't reach the park") 31 | 32 | // prints "Home" 33 | println(navigator.currentLocation) 34 | 35 | // throws an IllegalStateException 36 | navigator.navigateTo("Park") 37 | ``` 38 | 39 | In MockK, stubs are created by using the `mockk` and `every` functions. `mockk` creates your pretend object, and `every` lets you define canned answers for different functions on that pretend object. `every` starts a stubbing block and uses anonymous functions and [infix functions](https://kotlinlang.org/docs/reference/functions.html#infix-notation) to define the stub. 40 | 41 | Inside the stubbing block (between the opening curly bracket `{` and closing curly bracket `}`), you write the method you want to provide a canned answer for. `{ navigator.currentLocation }` tells MockK to make a canned answer for the `currentLocation` getter on the `navigator` object. 42 | 43 | To define what happens when the stubbed method is called, an answer function such as `returns` is used. `returns "Home"` tells MockK to always return the string `"Home"` when the `currentLocation` getter is called. 44 | 45 | Instead to returning successful values, stubbed methods can throw errors. `throws` indicates that the following value should be an exception to throw, rather than a value to return. When the stubbed method is called in your tests, it will always throw the given exception instance. 46 | -------------------------------------------------------------------------------- /layouts/_default/baseof.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ partial "docs/html-head" . }} 5 | {{ partial "docs/inject/head" . }} 6 | 7 | 8 | 9 | 10 |
11 | 16 | 17 |
18 |
19 | {{ template "header" . }} 20 |
21 | 22 | {{ partial "docs/inject/content-before" . }} 23 | {{ template "main" . }} 24 | {{ partial "docs/inject/content-after" . }} 25 | 26 |
27 | {{ template "footer" . }} 28 | {{ partial "docs/inject/footer" . }} 29 |
30 | 31 | {{ template "comments" . }} 32 | 33 | 34 |
35 | 36 | {{ if default true (default .Site.Params.BookToC .Params.BookToC) }} 37 | 42 | {{ end }} 43 |
44 | 45 | {{ partial "docs/inject/body" . }} 46 | 47 | 48 | 49 | 50 | {{ define "menu" }} 51 | {{ partial "docs/menu" . }} 52 | {{ end }} 53 | 54 | {{ define "header" }} 55 | {{ partial "docs/header" . }} 56 | 57 | {{ if default true (default .Site.Params.BookToC .Params.BookToC) }} 58 | 61 | {{ end }} 62 | {{ end }} 63 | 64 | {{ define "footer" }} 65 | {{ partial "docs/footer" . }} 66 | {{ end }} 67 | 68 | {{ define "comments" }} 69 | {{ if and .Content (default true (default .Site.Params.BookComments .Params.BookComments)) }} 70 |
71 | {{- partial "docs/comments" . -}} 72 |
73 | {{ end }} 74 | {{ end }} 75 | 76 | {{ define "main" }} 77 |
78 | {{- .Content -}} 79 |
80 | {{ end }} 81 | 82 | {{ define "toc" }} 83 | {{ partial "docs/toc" . }} 84 | {{ end }} 85 | -------------------------------------------------------------------------------- /layouts/partials/docs/html-head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{- with .Page.Params.BookHref -}} 8 | 9 | {{- end -}} 10 | 11 | {{ partial "docs/html-head-title" . }} 12 | 13 | {{- $manifest := resources.Get "manifest.json" | resources.ExecuteAsTemplate "manifest.json" . }} 14 | 15 | 16 | 17 | 18 | {{- range .Translations }} 19 | 20 | {{- end -}} 21 | 22 | 23 | {{- $styles := resources.Get "book.scss" | resources.ExecuteAsTemplate "book.scss" . | resources.ToCSS | resources.Minify | resources.Fingerprint }} 24 | 25 | 26 | {{- if default true .Site.Params.BookSearch -}} 27 | {{- $searchJSFile := printf "%s.search.js" .Language.Lang }} 28 | {{- $searchJS := resources.Get "search.js" | resources.ExecuteAsTemplate $searchJSFile . | resources.Minify | resources.Fingerprint }} 29 | 30 | 31 | {{ end -}} 32 | 33 | {{- if .Site.Params.BookServiceWorker -}} 34 | {{- $swJS := resources.Get "sw-register.js" | resources.ExecuteAsTemplate "sw.js" . | resources.Minify | resources.Fingerprint }} 35 | 36 | {{ end -}} 37 | 38 | {{- template "_internal/google_analytics_async.html" . -}} 39 | 40 | 41 | {{- with .OutputFormats.Get "rss" -}} 42 | {{ printf `` .Rel .MediaType.Type .Permalink $.Site.Title | safeHTML }} 43 | {{ end -}} 44 | 45 | {{ "" | safeHTML }} 49 | 50 | {{- define "integrity" -}} 51 | {{- if (urls.Parse .Permalink).Host -}} 52 | integrity="{{ .Data.Integrity }}" crossorigin="anonymous" 53 | {{- end -}} 54 | {{- end -}} 55 | -------------------------------------------------------------------------------- /content/docs/matching/with.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assertions with an argument 3 | summary: > 4 | Using `withArg` to run assertions in `verify` calls. 5 | weight: 40 6 | methods: 7 | - withArg 8 | - withNullableArg 9 | - coWithArg 10 | - coWithNullableArg 11 | --- 12 | 13 | # Run assertions with an argument 14 | 15 | There are some special argument matchers that can only be used when verifying that a mocked function was called. `withArg` and its variants allow you to capture an argument and run your own assertions on it without the need to set up a [capturing slot](capture.md). 16 | 17 | ```kotlin 18 | data class File( 19 | val name: String, 20 | val data: ByteArray 21 | ) 22 | 23 | interface FileNetwork { 24 | fun download(name: String): File 25 | fun upload(file: File) 26 | } 27 | ``` 28 | 29 | When using a capturing slot, testing the `FileNetwork.download` function looks like this: 30 | 31 | ```kotlin 32 | val network = mockk() 33 | val slot = slot() 34 | 35 | every { network.download(capture(slot)) } returns mockk() 36 | 37 | network.download("testfile") 38 | 39 | verify { 40 | network.download(any()) 41 | } 42 | assertTrue("testfile" == slot.captured) 43 | ``` 44 | 45 | `withArg` simplifies this code so no slot is needed. 46 | 47 | ```kotlin 48 | val network = mockk() 49 | 50 | every { network.download(any()) } returns mockk() 51 | 52 | network.download("testfile") 53 | 54 | verify { 55 | network.download(withArg { 56 | assertTrue("testfile" == it) 57 | }) 58 | } 59 | ``` 60 | 61 | ## Arrays and data classes 62 | 63 | `withArg` can be helpful when you use arguments that aren't easily compared, such as a data class containing arrays. The `equals()` function on an array works differently than on a `List`. Arrays are only equal if you compare with the exact same instance, while lists are equal if all of their items are equal. Since Kotlin data classes use the `equals()` function with each property, this array behaviour affects them. 64 | 65 | ```kotlin 66 | val expected = File("hello", data = "world".toByteArray()) 67 | 68 | network.upload(File("hello", data = "world".toByteArray())) 69 | 70 | // fails because the Files are not equal 71 | verify { 72 | network.upload(expected) 73 | } 74 | ``` 75 | 76 | In your test, you can choose to compare properties individually using `withArg`. 77 | 78 | ```kotlin 79 | val expected = File("hello", data = "world".toByteArray()) 80 | 81 | network.upload(File("hello", data = "world".toByteArray())) 82 | 83 | verify { 84 | network.upload(withArg { 85 | assertTrue(expected.name == it.name) 86 | assertTrue(expected.data contentEquals it.data) 87 | }) 88 | } 89 | ``` 90 | 91 | ## Nullable arguments 92 | 93 | `withNullableArg` is also provided by MockK when you wish to use it with a nullable argument. 94 | 95 | ## Coroutines 96 | 97 | MockK provides variants with `withArg` and `withNullableArg` that allow coroutine code to be executed. These variants are `coWithArg` and `coWithNullableArg`. If your assertions call a suspend function, these variants should be used. 98 | -------------------------------------------------------------------------------- /content/docs/mockito-migrate/verify.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "`verify`" 3 | summary: > 4 | `verify` that a method was called. 5 | weight: 40 6 | --- 7 | 8 | # `verify` 9 | 10 | Verifying that a method was called has similar syntax in Mockito and MockK. MockK uses inline functions and keyword arguments in place of Mockito's verification modes. 11 | 12 | ```kotlin 13 | // Mockito 14 | val mockedFile = mock(File::class.java) 15 | 16 | mockedFile.read() 17 | verify(mockedFile).read() 18 | ``` 19 | 20 | ```kotlin 21 | // MockK 22 | val mockedFile = mockk() 23 | 24 | mockedFile.read() 25 | verify { mockedFile.read() } 26 | ``` 27 | 28 | ## Verification Mode 29 | 30 | Mockito lets extra arguments such as `never()` be passed to verify in the second parameter, all of which implement a `VerificationMode` interface. MockK has equivalents for these modes as keyword arguments in `verify`. 31 | 32 | ### `never` 33 | 34 | ```kotlin 35 | // Mockito 36 | verify(mockedFile, never()).write() 37 | ``` 38 | 39 | ```kotlin 40 | // MockK 41 | verify(inverse = true) { mockedFile.write() } 42 | ``` 43 | 44 | ### `atLeast`/`atLeastOnce` 45 | 46 | ```kotlin 47 | // Mockito 48 | verify(mockedFile, atLeast(3)).read() 49 | verify(mockedFile, atLeastOnce()).write() 50 | ``` 51 | 52 | ```kotlin 53 | // MockK 54 | verify(atLeast = 3) { mockedFile.read() } 55 | verify(atLeast = 1) { mockedFile.write() } 56 | ``` 57 | 58 | ### `atMost`/`atMostOnce` 59 | 60 | ```kotlin 61 | // Mockito 62 | verify(mockedFile, atMost(3)).read() 63 | verify(mockedFile, atMostOnce()).write() 64 | ``` 65 | 66 | ```kotlin 67 | // MockK 68 | verify(atMost = 3) { mockedFile.read() } 69 | verify(atMost = 1) { mockedFile.write() } 70 | ``` 71 | 72 | ### `times` 73 | 74 | ```kotlin 75 | // Mockito 76 | verify(mockedFile, times(3)).read() 77 | ``` 78 | 79 | ```kotlin 80 | // MockK 81 | verify(exactly = 3) { mockedFile.read() } 82 | ``` 83 | 84 | ### `timeout` 85 | 86 | ```kotlin 87 | // Mockito 88 | verify(mockedFile, timeout(100)).readAsync() 89 | ``` 90 | 91 | ```kotlin 92 | // MockK 93 | verify(timeout = 100) { mockedFile.readAsync() } 94 | ``` 95 | 96 | ## `verifyNoInteractions` 97 | 98 | ```kotlin 99 | // Mockito 100 | verifyNoInteractions(mockOne) 101 | verifyNoInteractions(mockTwo, mockThree) 102 | ``` 103 | 104 | ```kotlin 105 | // MockK 106 | verify { mockOne wasNot Called } 107 | verify { listOf(mockTwo, mockThree) wasNot Called } 108 | ``` 109 | 110 | ## `verifyNoMoreInteractions` 111 | 112 | ```kotlin 113 | // Mockito 114 | verifyNoMoreInteractions(mockOne, mockTwo) 115 | ``` 116 | 117 | ```kotlin 118 | // MockK 119 | confirmVerified(mockOne, mockTwo) 120 | ``` 121 | 122 | ## Coroutines 123 | 124 | As MockK uses function literals to create stubs, small changes are needed to verify suspend functions. MockK provides functions prefixed with `co` as equivalents to other functions, such as `coVerify`. See [Coroutines and suspend functions](../mocking/coroutines.md) for more details. 125 | 126 | ```kotlin 127 | val mockedFile = mockk() 128 | 129 | coVerify { mockedFile.readAsync() } 130 | ``` 131 | -------------------------------------------------------------------------------- /layouts/partials/docs/inject/menu-before.html: -------------------------------------------------------------------------------- 1 | 2 | Written by 3 | 4 | Tiger Oakes 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /content/docs/mocking/annotation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Create many mocks quickly with annotations 3 | summary: > 4 | The `@MockK` and `@SpyK` shortcuts. 5 | weight: 100 6 | --- 7 | 8 | # Create many mocks quickly with annotations 9 | 10 | Sometimes you will need to create many mocks in your test class. As each mock needs to be declared as a property in the test class, then initialized in the test setup function, the amount of code needed to build all your mocks can grow very quickly. MockK provides a shorthand using annotations to make this simpler. 11 | 12 | ```kotlin 13 | class RepositoryTest { 14 | 15 | @MockK private lateinit var foodDatabase: FoodDatabase 16 | @MockK private lateinit var recipeDatabase: RecipeDatabase 17 | @MockK private lateinit var networkClient: NetworkClient 18 | @SpyK private var logger = Logger() 19 | 20 | @Before 21 | fun setup() { 22 | MockKAnnotations.init(this) 23 | } 24 | 25 | @Test 26 | fun testDatabaseAndNetwork() { 27 | // ... use foodDatabase, recipeDatabase, networkClient and debugger 28 | } 29 | } 30 | ``` 31 | 32 | Each property with the `@MockK` annotation is automatically mocked and ready to use in tests. This reduces repetition and makes your tests more readable. The above class is equivalent to: 33 | 34 | ```kotlin 35 | class RepositoryTest { 36 | 37 | private lateinit var foodDatabase: FoodDatabase 38 | private lateinit var recipeDatabase: RecipeDatabase 39 | private lateinit var networkClient: NetworkClient 40 | private lateinit var logger: Logger 41 | 42 | @Before 43 | fun setup() { 44 | foodDatabase = mockk() 45 | recipeDatabase = mockk() 46 | networkClient = mockk() 47 | logger = spyk(Logger()) 48 | } 49 | 50 | @Test 51 | fun testDatabaseAndNetwork() { 52 | // ... use foodDatabase, recipeDatabase, networkClient and debugger 53 | } 54 | } 55 | ``` 56 | 57 | ## Options 58 | 59 | `@MockK` annotations take the same options as the `mockk` function. If you wish to use a relaxed mock, the annotation looks similar to the equivalent `mockk` call: 60 | 61 | ```kotlin 62 | // Annotations 63 | class RepositoryTest { 64 | 65 | @MockK(relaxed = true) private lateinit var foodDatabase: FoodDatabase 66 | @MockK(relaxUnitFun = true) private lateinit var recipeDatabase: RecipeDatabase 67 | 68 | @Before 69 | fun setup() { 70 | MockKAnnotations.init(this) 71 | } 72 | } 73 | ``` 74 | 75 | ```kotlin 76 | // Long form 77 | class RepositoryTest { 78 | 79 | private lateinit var foodDatabase: FoodDatabase 80 | private lateinit var recipeDatabase: RecipeDatabase 81 | 82 | @Before 83 | fun setup() { 84 | foodDatabase = mockk(relaxed = true) 85 | recipeDatabase = mockk(relaxUnitFun = true) 86 | } 87 | } 88 | ``` 89 | 90 | In addition to `@MockK(relaxed = true)`, there is an equivalent `@RelaxedMockK` annotation. 91 | 92 | If options are shared across every annotated mock, they can be passed to the `init` call instead. 93 | 94 | ```kotlin 95 | class RepositoryTest { 96 | 97 | @MockK private lateinit var foodDatabase: FoodDatabase 98 | @MockK private lateinit var recipeDatabase: RecipeDatabase 99 | 100 | @Before 101 | fun setup() { 102 | MockKAnnotations.init(this, relaxed = true) 103 | } 104 | } 105 | ``` 106 | 107 | ## Spies 108 | 109 | TODO 110 | -------------------------------------------------------------------------------- /content/docs/mocking/static.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Mock singleton objects and static methods 3 | summary: > 4 | Advanced static mocking with `mockkStatic` and `mockkObject`. 5 | weight: 70 6 | --- 7 | 8 | # Mock singleton objects and static methods 9 | 10 | ## Mocking objects 11 | 12 | When you need a singleton in Kotlin, you can use an [`object`](https://kotlinlang.org/docs/tutorials/kotlin-for-py/objects-and-companion-objects.html). These specialized classes will only ever have one instance, so you can't mock them in the usual manner. Instead, MockK provides specialized functions to create object mocks. 13 | 14 | ```kotlin 15 | object FeatureFlags { 16 | val featureEnabled = true 17 | } 18 | 19 | mockkObject(FeatureFlags) 20 | every { FeatureFlags.featureEnabled } returns false 21 | 22 | // prints false 23 | println(FeatureFlags.featureEnabled) 24 | ``` 25 | 26 | Despite the name, object mocks behave more like [spies](./spy.md). If a method is not stubbed, then the real method will be called. This differs from regular mocks, where a method will either throw or do nothing if it is not stubbed. 27 | 28 | ```kotlin 29 | class Calculator1 { 30 | fun add(a: Int, b: Int): Int { 31 | return a + b 32 | } 33 | } 34 | 35 | object Calculator2 { 36 | fun add(a: Int, b: Int): Int { 37 | return a + b 38 | } 39 | } 40 | 41 | val calculator1 = mockk() 42 | mockkObject(Calculator2) 43 | 44 | // throws because the method was not stubbed 45 | println(calculator1.add(2, 2)) 46 | 47 | // returns the result from the real method 48 | println(Calculator2.add(2, 2)) 49 | ``` 50 | 51 | This approach works with any Kotlin object, which includes [`companion object`s](https://kotlinlang.org/docs/tutorials/kotlin-for-py/objects-and-companion-objects.html#companion-objects) and [`enum class`](https://kotlinlang.org/docs/reference/enum-classes.html) elements. 52 | 53 | ## Mocking static methods 54 | 55 | Sometimes you may end up working with Java code in your tests, which can have static methods. 56 | 57 | ```java 58 | package com.name.app; 59 | 60 | class Writer { 61 | public static File getFile(String path) { 62 | return new File(path); 63 | } 64 | } 65 | ``` 66 | 67 | Just like singleton objects, there will only ever be one version of static methods, so you cannot mock them in the usual manner. Again, MockK provides specialized functions to mock static methods. 68 | 69 | ```kotlin 70 | mockkStatic("com.name.app.Writer") 71 | ``` 72 | 73 | Rather than passing a reference to the class, you pass the class name as a string. You can also choose to pass in a reference to the class, and MockK will figure out the class name. 74 | 75 | ```kotlin 76 | mockkStatic(Writer::class) 77 | ``` 78 | 79 | Like object mocks, static mocks behave like [spies](./spy.md). The real method will be called if the method is not stubbed. 80 | 81 | ## Unmocking 82 | 83 | If you'd like to revert back to the real object, you can use the `unmockkObject` method. This removes any stubbed behaviour you may have added. 84 | 85 | ```kotlin 86 | object Calculator { 87 | fun add(a: Int, b: Int): Int { 88 | return a + b 89 | } 90 | } 91 | 92 | mockkObject(Calculator) 93 | every { Calculator.add(any(), any()) } returns 10 94 | 95 | // prints 10 96 | println(Calculator.add(2, 2)) 97 | 98 | unmockkObject(Calculator) 99 | 100 | // prints 4 101 | println(Calculator.add(2, 2)) 102 | ``` 103 | -------------------------------------------------------------------------------- /content/docs/mocking/answers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Create more complicated answers for stubs 3 | summary: > 4 | Using `answers` when `returns` just isn't enough. 5 | weight: 120 6 | --- 7 | 8 | Most [stubs](./stubbing.md) will use `returns` to always return the same value when the corresponding method is called. Sometimes, the method you're trying to mock may be more complicated and require a more advanced stub. 9 | 10 | If you want to change the result of a mocked method depending on its arguments, run additional code whenever a method is called, or just print out "Hello world" when a mock is used, `answers` is the tool you'll want to use. 11 | 12 | `answers` takes the place of `returns` after an `every` call. When using `returns`, it should be followed by a value to return. When using `answers`, it should be followed by a lambda function that is run when the mocked method is called. 13 | 14 | ```kotlin 15 | import io.mockk.every 16 | import io.mockk.mockk 17 | 18 | val navigator = mockk() 19 | every { navigator.currentLocation } returns "Home" 20 | every { navigator.currentLocation } answers { "Home" } 21 | ``` 22 | 23 | ## Side effects 24 | 25 | A function has "side effects" if it does something other than just returning a value, such as logging or mutating some outside state. `answers` lets you model side effects by putting additional statements inside its lambda function. 26 | 27 | ```kotlin 28 | every { navigator.currentLocation } answers { 29 | println("Hello world!") 30 | 31 | "Work" 32 | } 33 | 34 | // prints "Hello world!" 35 | val location = navigator.currentLocation 36 | // prints "Work" 37 | println(location) 38 | ``` 39 | 40 | ## Answer scope 41 | 42 | Inside of the `answers` lambda function, you can access information about the mocked method and how it was called. You can then use this to adjust the resulting answer. 43 | 44 | ```kotlin 45 | every { navigator.navigateTo(any()) } answers { 46 | val destination = firstArg() 47 | throw IllegalStateException("Can't reach $destination") 48 | } 49 | ``` 50 | 51 | These values are properties on the [`MockKAnswerScope`](https://mockk.io/#answer-scope) class. The scope is passed as a [receiver object](https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver), allowing variables to be called from the implicit `this` scope. 52 | 53 | ### Individual arguments 54 | 55 | Single arugments can be obtained using `firstArg()`, `secondArg()`, `thirdArg()`, and `lastArg()`. Other arguments can be obtained with `arg(n)`, where `n` is the index of the argument. For example, `arg(3)` would return the fourth argument. 56 | 57 | Arguments do not have static type checking. Instead, the type is casted automatically using generic types. 58 | 59 | ```kotlin 60 | every { calculator.add(any(), any()) } answers { 61 | // tries to cast the second argument to a string 62 | println(secondArg()) 63 | 0 64 | } 65 | ``` 66 | 67 | The above code will compile, but when the test is run a `ClassCastException` will be thrown because you cannot cast an `Int` to a `String`. 68 | 69 | ### All arguments 70 | 71 | The entire list of arguments can be obtained using `args`. `args` has the type `List`, so you will need to manually cast values in the list if you want to work with them. 72 | 73 | ```kotlin 74 | every { calculator.add(any(), any()) } answers { 75 | val numbers = args as List 76 | numbers.sum() 77 | } 78 | 79 | // prints "4" 80 | println(calculator.add(2, 2)) 81 | ``` 82 | 83 | If you only need to know the length of `args`, aka the number of arguments, you can use `nArgs`. 84 | 85 | TODO `call`, `invocation`, `matcher`, `self`, `method`, `captured`, `lambda`, `coroutine`, `nothing`, `fieldValue`, `fieldValueAny`, `value`, `valueAny`. 86 | -------------------------------------------------------------------------------- /config.yaml: -------------------------------------------------------------------------------- 1 | baseURL: https://notwoods.github.io/mockk-guidebook/ 2 | title: MockK Guidebook 3 | theme: book 4 | 5 | disableKinds: 6 | - RSS 7 | - taxonomy 8 | - taxonomyTerm 9 | - term 10 | 11 | # Book configuration 12 | enableGitInfo: true 13 | 14 | # Needed for mermaid/katex shortcodes 15 | markup: 16 | goldmark: 17 | renderer: 18 | unsafe: true 19 | tableOfContents: 20 | startLevel: 1 21 | 22 | # Multi-lingual mode config 23 | # There are different options to translate files 24 | # See https://gohugo.io/content-management/multilingual/#translation-by-filename 25 | # And https://gohugo.io/content-management/multilingual/#translation-by-content-directory 26 | languages: 27 | en: 28 | languageName: English 29 | contentDir: content 30 | weight: 1 31 | 32 | menu: 33 | # before: [] 34 | after: 35 | - name: "Github" 36 | url: "https://github.com/NotWoods/mockk-guidebook/" 37 | weight: 10 38 | 39 | params: 40 | # (Optional, default light) Sets color theme: light, dark or auto. 41 | # Theme 'auto' switches between dark and light modes based on browser/os preferences 42 | BookTheme: dark 43 | 44 | # (Optional, default true) Controls table of contents visibility on right side of pages. 45 | # Start and end levels can be controlled with markup.tableOfContents setting. 46 | # You can also specify this parameter per page in front matter. 47 | BookToC: true 48 | 49 | # (Optional, default none) Set the path to a logo for the book. If the logo is 50 | # /static/logo.png then the path would be logo.png 51 | # BookLogo: /logo.png 52 | 53 | # (Optional, default none) Set leaf bundle to render as side menu 54 | # When not specified file structure and weights will be used 55 | BookMenuBundle: /menu 56 | 57 | # (Optional, default docs) Specify root page to render child pages as menu. 58 | # Page is resoled by .GetPage function: https://gohugo.io/functions/getpage/ 59 | # For backward compatibility you can set '*' to render all sections to menu. Acts same as '/' 60 | # BookSection: docs 61 | 62 | # Set source repository location. 63 | # Used for 'Last Modified' and 'Edit this page' links. 64 | BookRepo: https://github.com/NotWoods/mockk-guidebook/ 65 | 66 | # Enable "Edit this page" links for 'doc' page type. 67 | # Disabled by default. Uncomment to enable. Requires 'BookRepo' param. 68 | # Edit path must point to root directory of repo. 69 | BookEditPath: edit/main 70 | 71 | # Configure the date format used on the pages 72 | # - In git information 73 | # - In blog posts 74 | BookDateFormat: "January 2, 2006" 75 | 76 | # (Optional, default true) Enables search function with flexsearch, 77 | # Index is built on fly, therefore it might slowdown your website. 78 | # Configuration for indexing can be adjusted in i18n folder per language. 79 | BookSearch: true 80 | 81 | # (Optional, default true) Enables comments template on pages 82 | # By default partals/docs/comments.html includes Disqus template 83 | # See https://gohugo.io/content-management/comments/#configure-disqus 84 | # Can be overwritten by same param in page frontmatter 85 | BookComments: false 86 | 87 | # /!\ This is an experimental feature, might be removed or changed at any time 88 | # (Optional, experimental, default false) Enables portable links and link checks in markdown pages. 89 | # Portable links meant to work with text editors and let you write markdown without {{< relref >}} shortcode 90 | # Theme will print warning if page referenced in markdown does not exists. 91 | BookPortableLinks: true 92 | 93 | # /!\ This is an experimental feature, might be removed or changed at any time 94 | # (Optional, experimental, default false) Enables service worker that caches visited pages and resources for offline use. 95 | BookServiceWorker: false 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MockK Guidebook 2 | 3 | 4 | 5 | A guide to using the [MockK testing library](https://mockk.io/). 6 | 7 | This resource is designed to help you learn how to use MockK, whether you're new to mocking or [transitioning from another framework](./content/docs/mockito-migrate). You can skim and skip around different pages. It's a living document, so it will be receiving updates to add more information over time. 8 | 9 | Written by
10 | 11 | 12 | 13 | Tiger Oakes 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /content/docs/mocking/verify.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Verify that functions were called 3 | summary: > 4 | Using `verify` to check that a function was used. 5 | weight: 20 6 | --- 7 | 8 | # Verify that functions were called 9 | 10 | When using mocked dependencies, you usually want to test that your code calls the correct functions. In MockK, this is accomplished using the `verify` function. 11 | 12 | Using `verify` to verify that a function was called looks a lot like using `every` for stubbing. A simple example is to call a method and immediately check that it was called. 13 | 14 | ```kotlin 15 | import io.mockk.every 16 | import io.mockk.mockk 17 | import io.mockk.verify 18 | 19 | val navigator = mockk() 20 | every { navigator.navigateTo(any()) } returns Unit 21 | 22 | navigator.navigateTo("Park") 23 | verify { navigator.navigateTo("Park") } 24 | ``` 25 | 26 | Similar to [stubbing with `every`](./stubbing.md), `verify` starts a verification block and uses anonymous functions and [infix functions](https://kotlinlang.org/docs/reference/functions.html#infix-notation) to define what will be verified. `verify` supports the same [argument matchers](../matching) as `every`, along with a few [additional matchers](../matching/with.md). 27 | 28 | Inside the verification block (between the opening curly bracket `{` and closing curly bracket `}`), you write the method you want to verify. `{ navigator.navigateTo("Park") }` tells MockK to check if the `navigateTo` method on the `navigator` object was called with the argument `"Park"`. 29 | 30 | ## Verifying dependencies 31 | 32 | In the previous simple example, verification isn't very helpful as it just checks that the previous line ran. Verification becomes more useful when you are testing other classes, that depend on mocked instances. Let's start testing a button. 33 | 34 | ```kotlin 35 | class Button { 36 | private var clickListener: (() -> Unit)? = null 37 | 38 | fun setOnClickListener(listener: () -> Unit) { 39 | clickListener = listener 40 | } 41 | 42 | fun performClick() { 43 | clickListener?.invoke() 44 | } 45 | } 46 | 47 | class NavigationView( 48 | private val navigator: Navigator 49 | ) { 50 | 51 | val goToParkButton = Button() 52 | 53 | init { 54 | goToParkButton.setOnClickListener { 55 | navigator.navigateTo("Park") 56 | } 57 | } 58 | } 59 | ``` 60 | 61 | A test for the above `NavigationView` class should check that clicking the `goToParkButton` tells the `navigator` to go to the park. If the navigator doesn't record where it goes, then it can be difficult to check that the button does its job correctly. This is a scenario where MockK can shine. 62 | 63 | ```kotlin 64 | // Mock the dependency needed for navigationView 65 | val navigator = mockk() 66 | every { navigator.navigateTo(any()) } returns Unit 67 | 68 | // Create the navigation view to test 69 | val navigationView = NavigationView(navigator) 70 | 71 | // Test the button in navigation view 72 | navigationView.goToParkButton.performClick() 73 | verify { navigator.navigateTo("Park") } 74 | ``` 75 | 76 | This test ensures that the button tells the navigator to go where we expect. If the `NavigationView` view gets changed in the future, the test will throw if this expectation is broken. 77 | 78 | ```diff 79 | goToParkButton.setOnClickListener { 80 | - navigator.navigateTo("Park") 81 | + navigator.navigateTo("Parka") 82 | } 83 | ``` 84 | 85 | ```kotlin 86 | navigationView.goToParkButton.performClick() 87 | // Throws as navigateTo("Park") was never called. 88 | // MockK will mention in the error that navigateTo("Parka") was called. 89 | verify { navigator.navigateTo("Park") } 90 | ``` 91 | 92 | ## Verifying that any mock functions is never called 93 | 94 | ```kotlin 95 | verify { navigator wasNot Called } 96 | ``` 97 | 98 | ## Verifying that a function is never called 99 | 100 | ```kotlin 101 | verify(inverse = true) { navigator.navigateTo("Park") } 102 | verify(exactly = 0) { navigator.navigateTo("Park") } 103 | ``` 104 | 105 | ## Verifying a function is called a certain number of times 106 | 107 | ```kotlin 108 | verify(exactly = 1) { navigator.navigateTo("Park") } 109 | verify(atLeast = 1, atMost = 1) { navigator.navigateTo("Park") } 110 | ``` 111 | 112 | ### Using a range 113 | 114 | ```kotlin 115 | verify(atLeast = 2, atMost = 3) { navigator.navigateTo("Park") } 116 | ``` 117 | 118 | In the sample test will be green in the following cases: 119 | 120 | 1. Function called two times 121 | 2. Function called three times 122 | 123 | ## Verifying multiple functions 124 | 125 | TODO: `ordering`, `verifyAll`, `verifySequence`, `verifyOrder` 126 | 127 | ## Confirming all calls were verified 128 | 129 | TODO: `confirmVerified`, `excludeRecords` 130 | -------------------------------------------------------------------------------- /content/docs/mockito-migrate/when.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "`when` and `do*`" 3 | summary: > 4 | `when(x).thenReturn(y)`, `doReturn`, and more. 5 | weight: 10 6 | --- 7 | 8 | # `when` and `do*` 9 | 10 | Mockito provides two similar approaches for stubbing behaviour on a mock: the `when` method and the `do*` family of methods. 11 | 12 | Most stubs in Mockito are written with `when` at the beginning of the line, following the format "**when** the method is called **then** return something". Stubs written with the `when` method look like this: 13 | 14 | ```kotlin 15 | val mockedFile = mock(File::class.java) 16 | 17 | `when`(mockedFile.read()).thenReturn("hello world") 18 | ``` 19 | 20 | Sometimes this syntax cannot be used in Mockito, so an alternative approach is available. `doReturn` and the related `doThrow`, `doAnswer`, `doNothing`, and `doCallRealMethod` methods are used for void methods, spies, and other occasions where the `when` method cannot be used. Stubs written with the `do*` family of methods look like this: 21 | 22 | ```kotlin 23 | val mockedFile = mock(File::class.java) 24 | 25 | doReturn("hello world").`when`(mockedFile).read() 26 | ``` 27 | 28 | In MockK, all [stubs](../mocking/stubbing.md) can be written with the `every` method. `every` starts a stubbing block and uses anonymous functions and [infix functions](https://kotlinlang.org/docs/reference/functions.html#infix-notation) to define the stub. The syntax looks like this: 29 | 30 | ```kotlin 31 | val mockedFile = mockk() 32 | 33 | every { mockedFile.read() } returns "hello world" 34 | ``` 35 | 36 | MockK provides alternatives for many types of answers that Mockito supports for stubbing. 37 | 38 | ## `thenReturn`/`doReturn` 39 | 40 | Returning a value is probably the most common stub to create. In Mockito, the syntax can look like one of two approaches: 41 | 42 | ```kotlin 43 | val mockedFile = mock(File::class.java) 44 | 45 | `when`(mockedFile.read()).thenReturn("hello world") 46 | doReturn("hello world").`when`(mockedFile).read() 47 | ``` 48 | 49 | In MockK, an infix function is used instead. 50 | 51 | ```kotlin 52 | val mockedFile = mockk() 53 | 54 | every { mockedFile.read() } returns "hello world" 55 | ``` 56 | 57 | ## `thenThrow`/`doThrow` 58 | 59 | Rather than returning values, stubs can throw errors. Mockito lets exceptions be specified with one of two approaches: 60 | 61 | ```kotlin 62 | val mockedFile = mock(File::class.java) 63 | 64 | `when`(mockedFile.read()).thenThrow(RuntimeException()) 65 | doThrow(RuntimeException()).`when`(mockedFile).read() 66 | ``` 67 | 68 | MockK provides the `throws` infix method to throw in stubs. 69 | 70 | ```kotlin 71 | val mockedFile = mockk() 72 | 73 | every { mockedFile.read() } throws RuntimeException() 74 | ``` 75 | 76 | ## `doNothing` 77 | 78 | See [Migrating from Mockito: `void` methods](./void.md) 79 | 80 | ## `thenAnswer`/`then`/`doAnswer` 81 | 82 | Mockito allows arbitrary callbacks to be used for stubs with the `Answer` interface. `Answer` only contains a single method, so Kotlin allows a function literal to be used instead through [SAM conversion](https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions). 83 | 84 | ```kotlin 85 | val mockedFile = mock(File::class.java) 86 | 87 | `when`(mockedFile.write(any())).thenAnswer { invocation -> 88 | println("called with arguments: " + invocation.arguments.joinToString()) 89 | Unit 90 | } 91 | `when`(mockedFile.write(any())).then { invocation -> 92 | println("called with arguments: " + invocation.arguments.joinToString()) 93 | Unit 94 | } 95 | doAnswer { invocation -> 96 | println("called with arguments: " + invocation.arguments.joinToString()) 97 | Unit 98 | }.`when`(mockedFile).write(any()) 99 | ``` 100 | 101 | MockK provides an equivalent infix function that also uses function literals. 102 | 103 | ```kotlin 104 | val mockedFile = mockk() 105 | 106 | every { mockedFile.write(any()) } answers { call -> 107 | println("called with arguments: " + call.invocation.args.joinToString()) 108 | Unit 109 | } 110 | ``` 111 | 112 | ## Consecutive calls 113 | 114 | Mockito additionally lets different return values be stubbed for the same method call, such as for mocking an iterator. 115 | 116 | ```kotlin 117 | val mockedFile = mock(File::class.java) 118 | 119 | // Chain multiple calls 120 | `when`(mockedFile.read()).thenReturn("read 1").thenReturn("read 2").thenReturn("read 3") 121 | // Shorthand 122 | `when`(mockedFile.read()).thenReturn("read 1", "read 2", "read 3") 123 | doReturn("read 1", "read 2", "read 3").`when`(mockedFile).read() 124 | // Use different answer types 125 | `when`(mockedFile.read()) 126 | .thenReturn("successful read") 127 | .thenThrow(RuntimeException()) 128 | ``` 129 | 130 | Additional answers is supported in MockK using various infix functions. 131 | 132 | ```kotlin 133 | val mockedFile = mockk() 134 | 135 | // Chain multiple calls 136 | every { mockedFile.read() } returns "read 1" andThen "read 2" andThen "read 3" 137 | // Shorthand using a list 138 | every { mockedFile.read() } returnsMany listOf("read 1", "read 2", "read 3") 139 | every { mockedFile.read() } andThenMany listOf("read 1", "read 2", "read 3") 140 | // Use different answer types 141 | every { mockedFile.read() } returns "successful read" andThenThrows RuntimeException() 142 | ``` 143 | 144 | ## Coroutines 145 | 146 | As MockK uses function literals to create stubs, small changes are needed to stub suspend functions. MockK provides functions prefixed with `co` as equivalents to other functions, such as `coEvery` and `coAnswers`. See [Coroutines and suspend functions](../mocking/coroutines.md) for more details. 147 | 148 | ```kotlin 149 | val mockedFile = mockk() 150 | 151 | coEvery { mockedFile.readAsync() } returns "hello world" 152 | coEvery { mockedFile.writeAsync(any()) } coAnswers { call -> 153 | doAsyncWork() 154 | Unit 155 | } 156 | ``` 157 | -------------------------------------------------------------------------------- /resources/_gen/assets/scss/book.scss_50fc8c04e12a2f59027287995557ceff.content: -------------------------------------------------------------------------------- 1 | @charset "UTF-8";:root{--gray-100:rgba(255, 255, 255, 0.1);--gray-200:rgba(255, 255, 255, 0.2);--gray-500:rgba(255, 255, 255, 0.5);--color-link:#84b2ff;--color-visited-link:#b88dff;--body-background:#343a40;--body-font-color:#e9ecef;--icon-filter:brightness(0) invert(1);--hint-color-info:#6bf;--hint-color-warning:#fd6;--hint-color-danger:#f66}/*!normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css*/html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}.flex{display:flex}.flex-auto{flex:auto}.flex-even{flex:1 1}.flex-wrap{flex-wrap:wrap}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.align-center{align-items:center}.mx-auto{margin:0 auto}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.hidden{display:none}input.toggle{height:0;width:0;overflow:hidden;opacity:0;position:absolute}.clearfix::after{content:"";display:table;clear:both}html{font-size:16px;scroll-behavior:smooth;touch-action:manipulation}body{min-width:0;color:var(--body-font-color);background:var(--body-background);letter-spacing:.33px;font-weight:400;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;box-sizing:border-box}body *{box-sizing:inherit}h1,h2,h3,h4,h5{font-weight:400}a{text-decoration:none;color:var(--color-link)}img{vertical-align:baseline}:focus{outline-style:auto;outline-color:currentColor;outline-color:-webkit-focus-ring-color}aside nav ul{padding:0;margin:0;list-style:none}aside nav ul li{margin:1em 0;position:relative}aside nav ul a{display:block}aside nav ul a:hover{opacity:.5}aside nav ul ul{padding-inline-start:1rem}ul.pagination{display:flex;justify-content:center;list-style-type:none}ul.pagination .page-item a{padding:1rem}.container{max-width:80rem;margin:0 auto}.book-icon{filter:var(--icon-filter)}.book-brand{margin-top:0;margin-bottom:1rem}.book-brand img{height:1.5em;width:1.5em;margin-inline-end:.5rem}.book-menu{flex:0 0 16rem;font-size:.875rem}.book-menu .book-menu-content{width:16rem;padding:1rem;background:var(--body-background);position:fixed;top:0;bottom:0;overflow-x:hidden;overflow-y:auto}.book-menu a,.book-menu label{color:inherit;cursor:pointer;word-wrap:break-word}.book-menu a.active{color:var(--color-link)}.book-menu input.toggle+label+ul{display:none}.book-menu input.toggle:checked+label+ul{display:block}.book-menu input.toggle+label::after{content:"▸"}.book-menu input.toggle:checked+label::after{content:"▾"}body[dir=rtl] .book-menu input.toggle+label::after{content:"◂"}body[dir=rtl] .book-menu input.toggle:checked+label::after{content:"▾"}.book-section-flat{margin:2rem 0}.book-section-flat>a,.book-section-flat>span,.book-section-flat>label{font-weight:bolder}.book-section-flat>ul{padding-inline-start:0}.book-page{min-width:0;flex-grow:1;padding:1rem}.book-post{margin-bottom:3rem}.book-header{display:none;margin-bottom:1rem}.book-header label{line-height:0}.book-header img.book-icon{height:1.5em;width:1.5em}.book-search{position:relative;margin:1rem 0;border-bottom:1px solid transparent}.book-search input{width:100%;padding:.5rem;border:0;border-radius:.25rem;background:var(--gray-100);color:var(--body-font-color)}.book-search input:required+.book-search-spinner{display:block}.book-search .book-search-spinner{position:absolute;top:0;margin:.5rem;margin-inline-start:calc(100% - 1.5rem);width:1rem;height:1rem;border:1px solid transparent;border-top-color:var(--body-font-color);border-radius:50%;animation:spin 1s ease infinite}@keyframes spin{100%{transform:rotate(360deg)}}.book-search small{opacity:.5}.book-toc{flex:0 0 16rem;font-size:.75rem}.book-toc .book-toc-content{width:16rem;padding:1rem;position:fixed;top:0;bottom:0;overflow-x:hidden;overflow-y:auto}.book-toc img{height:1em;width:1em}.book-toc nav>ul>li:first-child{margin-top:0}.book-footer{padding-top:1rem;font-size:.875rem}.book-footer img{height:1em;width:1em;margin-inline-end:.5rem}.book-comments{margin-top:1rem}.book-languages{margin-block-end:2rem}.book-languages .book-icon{height:1em;width:1em;margin-inline-end:.5em}.book-languages ul{padding-inline-start:1.5em}.book-menu-content,.book-toc-content,.book-page,.book-header aside,.markdown{transition:.2s ease-in-out;transition-property:transform,margin,opacity,visibility;will-change:transform,margin,opacity}@media screen and (max-width:56rem){#menu-control,#toc-control{display:inline}.book-menu{visibility:hidden;margin-inline-start:-16rem;font-size:16px;z-index:1}.book-toc{display:none}.book-header{display:block}#menu-control:focus~main label[for=menu-control]{outline-style:auto;outline-color:currentColor;outline-color:-webkit-focus-ring-color}#menu-control:checked~main .book-menu{visibility:initial}#menu-control:checked~main .book-menu .book-menu-content{transform:translateX(16rem);box-shadow:0 0 .5rem rgba(0,0,0,.1)}#menu-control:checked~main .book-page{opacity:.25}#menu-control:checked~main .book-menu-overlay{display:block;position:absolute;top:0;bottom:0;left:0;right:0}#toc-control:focus~main label[for=toc-control]{outline-style:auto;outline-color:currentColor;outline-color:-webkit-focus-ring-color}#toc-control:checked~main .book-header aside{display:block}body[dir=rtl] #menu-control:checked~main .book-menu .book-menu-content{transform:translateX(-16rem)}}@media screen and (min-width:80rem){.book-page,.book-menu .book-menu-content,.book-toc .book-toc-content{padding:2rem 1rem}}@font-face{font-family:roboto;font-style:normal;font-weight:400;font-display:swap;src:local(""),url(fonts/roboto-v27-latin-regular.woff2)format("woff2"),url(fonts/roboto-v27-latin-regular.woff)format("woff")}@font-face{font-family:roboto;font-style:normal;font-weight:700;font-display:swap;src:local(""),url(fonts/roboto-v27-latin-700.woff2)format("woff2"),url(fonts/roboto-v27-latin-700.woff)format("woff")}@font-face{font-family:roboto mono;font-style:normal;font-weight:400;font-display:swap;src:local(""),url(fonts/roboto-mono-v13-latin-regular.woff2)format("woff2"),url(fonts/roboto-mono-v13-latin-regular.woff)format("woff")}body{font-family:roboto,sans-serif}code{font-family:roboto mono,monospace}@media print{.book-menu,.book-footer,.book-toc{display:none}.book-header,.book-header aside{display:block}main{display:block!important}}.markdown{line-height:1.6}.markdown>:first-child{margin-top:0}.markdown h1,.markdown h2,.markdown h3,.markdown h4,.markdown h5,.markdown h6{font-weight:400;line-height:1;margin-top:1.5em;margin-bottom:1rem}.markdown h1 a.anchor,.markdown h2 a.anchor,.markdown h3 a.anchor,.markdown h4 a.anchor,.markdown h5 a.anchor,.markdown h6 a.anchor{opacity:0;font-size:.75em;vertical-align:middle;text-decoration:none}.markdown h1:hover a.anchor,.markdown h1 a.anchor:focus,.markdown h2:hover a.anchor,.markdown h2 a.anchor:focus,.markdown h3:hover a.anchor,.markdown h3 a.anchor:focus,.markdown h4:hover a.anchor,.markdown h4 a.anchor:focus,.markdown h5:hover a.anchor,.markdown h5 a.anchor:focus,.markdown h6:hover a.anchor,.markdown h6 a.anchor:focus{opacity:initial}.markdown h4,.markdown h5,.markdown h6{font-weight:bolder}.markdown h5{font-size:.875em}.markdown h6{font-size:.75em}.markdown b,.markdown optgroup,.markdown strong{font-weight:bolder}.markdown a{text-decoration:none}.markdown a:hover{text-decoration:underline}.markdown a:visited{color:var(--color-visited-link)}.markdown img{max-width:100%;height:auto}.markdown code{padding:0 .25rem;background:var(--gray-200);border-radius:.25rem;font-size:.875em}.markdown pre{padding:1rem;background:var(--gray-100);border-radius:.25rem;overflow-x:auto}.markdown pre code{padding:0;background:0 0}.markdown p{word-wrap:break-word}.markdown blockquote{margin:1rem 0;padding:.5rem 1rem .5rem .75rem;border-inline-start:.25rem solid var(--gray-200);border-radius:.25rem}.markdown blockquote :first-child{margin-top:0}.markdown blockquote :last-child{margin-bottom:0}.markdown table{overflow:auto;display:block;border-spacing:0;border-collapse:collapse;margin-top:1rem;margin-bottom:1rem}.markdown table tr th,.markdown table tr td{padding:.5rem 1rem;border:1px solid var(--gray-200)}.markdown table tr:nth-child(2n){background:var(--gray-100)}.markdown hr{height:1px;border:none;background:var(--gray-200)}.markdown ul,.markdown ol{padding-inline-start:2rem}.markdown dl dt{font-weight:bolder;margin-top:1rem}.markdown dl dd{margin-inline-start:0;margin-bottom:1rem}.markdown .highlight table tr td:nth-child(1) pre{margin:0;padding-inline-end:0}.markdown .highlight table tr td:nth-child(2) pre{margin:0;padding-inline-start:0}.markdown details{padding:1rem;border:1px solid var(--gray-200);border-radius:.25rem}.markdown details summary{line-height:1;padding:1rem;margin:-1rem;cursor:pointer}.markdown details[open] summary{margin-bottom:0}.markdown figure{margin:1rem 0}.markdown figure figcaption p{margin-top:0}.markdown-inner>:first-child{margin-top:0}.markdown-inner>:last-child{margin-bottom:0}.markdown .book-expand{margin-top:1rem;margin-bottom:1rem;border:1px solid var(--gray-200);border-radius:.25rem;overflow:hidden}.markdown .book-expand .book-expand-head{background:var(--gray-100);padding:.5rem 1rem;cursor:pointer}.markdown .book-expand .book-expand-content{display:none;padding:1rem}.markdown .book-expand input[type=checkbox]:checked+.book-expand-content{display:block}.markdown .book-tabs{margin-top:1rem;margin-bottom:1rem;border:1px solid var(--gray-200);border-radius:.25rem;overflow:hidden;display:flex;flex-wrap:wrap}.markdown .book-tabs label{display:inline-block;padding:.5rem 1rem;border-bottom:1px transparent;cursor:pointer}.markdown .book-tabs .book-tabs-content{order:999;width:100%;border-top:1px solid var(--gray-100);padding:1rem;display:none}.markdown .book-tabs input[type=radio]:checked+label{border-bottom:1px solid var(--color-link)}.markdown .book-tabs input[type=radio]:checked+label+.book-tabs-content{display:block}.markdown .book-tabs input[type=radio]:focus+label{outline-style:auto;outline-color:currentColor;outline-color:-webkit-focus-ring-color}.markdown .book-columns{margin-left:-1rem;margin-right:-1rem}.markdown .book-columns>div{margin:1rem 0;min-width:0;padding:0 1rem}.markdown a.book-btn{display:inline-block;font-size:.875rem;color:var(--color-link);line-height:2rem;padding:0 1rem;border:1px solid var(--color-link);border-radius:.25rem;cursor:pointer}.markdown a.book-btn:hover{text-decoration:none}.markdown .book-hint.info{border-color:#6bf;background-color:rgba(102,187,255,.1)}.markdown .book-hint.warning{border-color:#fd6;background-color:rgba(255,221,102,.1)}.markdown .book-hint.danger{border-color:#f66;background-color:rgba(255,102,102,.1)}a del{opacity:.5}.kofi{display:block;text-align:center;margin-top:1rem}.author{display:block;margin-bottom:2rem}.logo-icon{transition:opacity .3s linear}.logo-icon--color,.author:hover .logo-icon--monochrome{opacity:0}.author:hover .logo-icon--color{opacity:1}.text-over path{stroke-dasharray:25;stroke-dashoffset:0;transition:stroke-dashoffset .5s linear}.author:hover .text-over path{stroke-dashoffset:25}.book-menu nav{max-width:calc(100vw - 2rem)}.book-toc .book-toc-inner nav{width:auto;padding:0;position:static;overflow-x:unset;overflow-y:unset}.book-toc-inner{width:16rem;padding:1rem;position:fixed;top:0;bottom:0;overflow-x:hidden;overflow-y:auto}@media screen and (min-width:80rem){.book-toc .book-toc-inner nav{padding:0}.book-toc-inner{padding:2rem 1rem}} -------------------------------------------------------------------------------- /resources/_gen/assets/scss/mockk-guidebook/book.scss_50fc8c04e12a2f59027287995557ceff.content: -------------------------------------------------------------------------------- 1 | :root{--gray-100: rgba(255, 255, 255, 0.1);--gray-200: rgba(255, 255, 255, 0.2);--gray-500: rgba(255, 255, 255, 0.5);--color-link: #84b2ff;--color-visited-link: #b88dff;--body-background: #343a40;--body-font-color: #e9ecef;--icon-filter: brightness(0) invert(1);--hint-color-info: #6bf;--hint-color-warning: #fd6;--hint-color-danger: #f66}/*!normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css*/html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}.flex{display:flex}.flex-auto{flex:1 1 auto}.flex-even{flex:1 1}.flex-wrap{flex-wrap:wrap}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.align-center{align-items:center}.mx-auto{margin:0 auto}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.hidden{display:none}input.toggle{height:0;width:0;overflow:hidden;opacity:0;position:absolute}.clearfix::after{content:"";display:table;clear:both}html{font-size:16px;scroll-behavior:smooth;touch-action:manipulation}body{min-width:0;color:var(--body-font-color);background:var(--body-background);letter-spacing:.33px;font-weight:400;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;box-sizing:border-box}body *{box-sizing:inherit}h1,h2,h3,h4,h5{font-weight:400}a{text-decoration:none;color:var(--color-link)}img{vertical-align:baseline}:focus{outline-style:auto;outline-color:currentColor;outline-color:-webkit-focus-ring-color}aside nav ul{padding:0;margin:0;list-style:none}aside nav ul li{margin:1em 0;position:relative}aside nav ul a{display:block}aside nav ul a:hover{opacity:.5}aside nav ul ul{padding-inline-start:1rem}ul.pagination{display:flex;justify-content:center;list-style-type:none}ul.pagination .page-item a{padding:1rem}.container{max-width:80rem;margin:0 auto}.book-icon{filter:var(--icon-filter)}.book-brand{margin-top:0}.book-brand img{height:1.5em;width:auto;vertical-align:middle;margin-inline-end:.5rem}.book-menu{flex:0 0 16rem;font-size:.875rem}.book-menu nav{width:16rem;padding:1rem;background:var(--body-background);position:fixed;top:0;bottom:0;overflow-x:hidden;overflow-y:auto}.book-menu a,.book-menu label{color:inherit;cursor:pointer;word-wrap:break-word}.book-menu a.active{color:var(--color-link)}.book-menu input.toggle+label+ul{display:none}.book-menu input.toggle:checked+label+ul{display:block}.book-section-flat{margin-bottom:2rem}.book-section-flat:not(:first-child){margin-top:2rem}.book-section-flat>a,.book-section-flat>span,.book-section-flat>label{font-weight:bolder}.book-section-flat>ul{padding-inline-start:0}.book-page{min-width:0;flex-grow:1;padding:1rem}.book-post{margin-bottom:3rem}.book-header{display:none;margin-bottom:1rem}.book-header label{line-height:0}.book-search{position:relative;margin:1rem 0;border-bottom:1px solid transparent}.book-search input{width:100%;padding:.5rem;border:0;border-radius:.25rem;background:var(--gray-100);color:var(--body-font-color)}.book-search input:required+.book-search-spinner{display:block}.book-search .book-search-spinner{position:absolute;top:0;margin:.5rem;margin-inline-start:calc(100% - 1.5rem);width:1rem;height:1rem;border:1px solid transparent;border-top-color:var(--body-font-color);border-radius:50%;animation:spin 1s ease infinite}@keyframes spin{100%{transform:rotate(360deg)}}.book-search small{opacity:.5}.book-toc{flex:0 0 16rem;font-size:.75rem}.book-toc nav{width:16rem;padding:1rem;position:fixed;top:0;bottom:0;overflow-x:hidden;overflow-y:auto}.book-toc img{height:1em}.book-toc nav>ul>li:first-child{margin-top:0}.book-footer{padding-top:1rem;font-size:.875rem}.book-footer img{height:1em;margin-inline-end:.5rem}.book-comments{margin-top:1rem}.book-languages{position:relative;overflow:visible;padding:1rem;margin:-1rem}.book-languages ul{margin:0;padding:0;list-style:none}.book-languages ul li{white-space:nowrap;cursor:pointer}.book-languages:hover .book-languages-list,.book-languages:focus .book-languages-list,.book-languages:focus-within .book-languages-list{display:block}.book-languages .book-languages-list{display:none;position:absolute;bottom:100%;left:0;padding:.5rem 0;background:var(--body-background);box-shadow:0 0 .25rem rgba(0,0,0,.1)}.book-languages .book-languages-list li img{opacity:.25}.book-languages .book-languages-list li.active img,.book-languages .book-languages-list li:hover img{opacity:initial}.book-languages .book-languages-list a{color:inherit;padding:.5rem 1rem}.book-home{padding:1rem}aside nav,.book-page,.book-header aside,.markdown{transition:.2s ease-in-out;transition-property:transform,margin,opacity,visibility;will-change:transform,margin,opacity}@media screen and (max-width:56rem){#menu-control,#toc-control{display:inline}.book-menu{visibility:hidden;margin-inline-start:-16rem;font-size:16px;z-index:1}.book-toc{display:none}.book-header{display:block}#menu-control:focus~main label[for=menu-control]{outline-style:auto;outline-color:currentColor;outline-color:-webkit-focus-ring-color}#menu-control:checked~main .book-menu{visibility:initial}#menu-control:checked~main .book-menu nav{transform:translateX(16rem);box-shadow:0 0 .5rem rgba(0,0,0,.1)}#menu-control:checked~main .book-page{opacity:.25}#menu-control:checked~main .book-menu-overlay{display:block;position:absolute;top:0;bottom:0;left:0;right:0}#toc-control:focus~main label[for=toc-control]{outline-style:auto;outline-color:currentColor;outline-color:-webkit-focus-ring-color}#toc-control:checked~main .book-header aside{display:block}body[dir=rtl] #menu-control:checked+main .book-menu nav{transform:translateX(-16rem)}}@media screen and (min-width:80rem){.book-page,.book-menu nav,.book-toc nav{padding:2rem 1rem}}@font-face{font-family:roboto;font-style:italic;font-weight:300;font-display:swap;src:local("Roboto Light Italic"),local("Roboto-LightItalic"),url(fonts/roboto-v19-latin-300italic.woff2)format("woff2"),url(fonts/roboto-v19-latin-300italic.woff)format("woff")}@font-face{font-family:roboto;font-style:normal;font-weight:400;font-display:swap;src:local("Roboto"),local("Roboto-Regular"),url(fonts/roboto-v19-latin-regular.woff2)format("woff2"),url(fonts/roboto-v19-latin-regular.woff)format("woff")}@font-face{font-family:roboto;font-style:normal;font-weight:700;font-display:swap;src:local("Roboto Bold"),local("Roboto-Bold"),url(fonts/roboto-v19-latin-700.woff2)format("woff2"),url(fonts/roboto-v19-latin-700.woff)format("woff")}@font-face{font-family:roboto mono;font-style:normal;font-weight:400;font-display:swap;src:local("Roboto Mono"),local("RobotoMono-Regular"),url(fonts/roboto-mono-v6-latin-regular.woff2)format("woff2"),url(fonts/roboto-mono-v6-latin-regular.woff)format("woff")}body{font-family:roboto,sans-serif}code{font-family:roboto mono,monospace}@media print{.book-menu,.book-footer,.book-toc{display:none}.book-header,.book-header aside{display:block}main{display:block!important}}.markdown{line-height:1.6}.markdown>:first-child{margin-top:0}.markdown h1,.markdown h2,.markdown h3,.markdown h4,.markdown h5,.markdown h6{font-weight:400;line-height:1;margin-top:1.5em;margin-bottom:1rem}.markdown h1 a.anchor,.markdown h2 a.anchor,.markdown h3 a.anchor,.markdown h4 a.anchor,.markdown h5 a.anchor,.markdown h6 a.anchor{opacity:0;font-size:.75em;vertical-align:middle;text-decoration:none}.markdown h1:hover a.anchor,.markdown h1 a.anchor:focus,.markdown h2:hover a.anchor,.markdown h2 a.anchor:focus,.markdown h3:hover a.anchor,.markdown h3 a.anchor:focus,.markdown h4:hover a.anchor,.markdown h4 a.anchor:focus,.markdown h5:hover a.anchor,.markdown h5 a.anchor:focus,.markdown h6:hover a.anchor,.markdown h6 a.anchor:focus{opacity:initial}.markdown h4,.markdown h5,.markdown h6{font-weight:bolder}.markdown h5{font-size:.875em}.markdown h6{font-size:.75em}.markdown b,.markdown optgroup,.markdown strong{font-weight:bolder}.markdown a{text-decoration:none}.markdown a:hover{text-decoration:underline}.markdown a:visited{color:var(--color-visited-link)}.markdown img{max-width:100%}.markdown code{padding:0 .25rem;background:var(--gray-200);border-radius:.25rem;font-size:.875em}.markdown pre{padding:1rem;background:var(--gray-100);border-radius:.25rem;overflow-x:auto}.markdown pre code{padding:0;background:0 0}.markdown blockquote{margin:1rem 0;padding:.5rem 1rem .5rem .75rem;border-inline-start:.25rem solid var(--gray-200);border-radius:.25rem}.markdown blockquote :first-child{margin-top:0}.markdown blockquote :last-child{margin-bottom:0}.markdown table{overflow:auto;display:block;border-spacing:0;border-collapse:collapse;margin-top:1rem;margin-bottom:1rem}.markdown table tr th,.markdown table tr td{padding:.5rem 1rem;border:1px solid var(--gray-200)}.markdown table tr:nth-child(2n){background:var(--gray-100)}.markdown hr{height:1px;border:none;background:var(--gray-200)}.markdown ul,.markdown ol{padding-inline-start:2rem}.markdown dl dt{font-weight:bolder;margin-top:1rem}.markdown dl dd{margin-inline-start:1rem;margin-bottom:1rem}.markdown .highlight table tr td:nth-child(1) pre{margin:0;padding-inline-end:0}.markdown .highlight table tr td:nth-child(2) pre{margin:0;padding-inline-start:0}.markdown details{padding:1rem;border:1px solid var(--gray-200);border-radius:.25rem}.markdown details summary{line-height:1;padding:1rem;margin:-1rem;cursor:pointer}.markdown details[open] summary{margin-bottom:0}.markdown figure{margin:1rem 0}.markdown figure figcaption p{margin-top:0}.markdown-inner>:first-child{margin-top:0}.markdown-inner>:last-child{margin-bottom:0}.markdown .book-expand{margin-top:1rem;margin-bottom:1rem;border:1px solid var(--gray-200);border-radius:.25rem;overflow:hidden}.markdown .book-expand .book-expand-head{background:var(--gray-100);padding:.5rem 1rem;cursor:pointer}.markdown .book-expand .book-expand-content{display:none;padding:1rem}.markdown .book-expand input[type=checkbox]:checked+.book-expand-content{display:block}.markdown .book-tabs{margin-top:1rem;margin-bottom:1rem;border:1px solid var(--gray-200);border-radius:.25rem;overflow:hidden;display:flex;flex-wrap:wrap}.markdown .book-tabs label{display:inline-block;padding:.5rem 1rem;border-bottom:1px transparent;cursor:pointer}.markdown .book-tabs .book-tabs-content{order:999;width:100%;border-top:1px solid var(--gray-100);padding:1rem;display:none}.markdown .book-tabs input[type=radio]:checked+label{border-bottom:1px solid var(--color-link)}.markdown .book-tabs input[type=radio]:checked+label+.book-tabs-content{display:block}.markdown .book-tabs input[type=radio]:focus+label{outline-style:auto;outline-color:currentColor;outline-color:-webkit-focus-ring-color}.markdown .book-columns{margin-left:-1rem;margin-right:-1rem}.markdown .book-columns>div{margin:1rem 0;min-width:0;padding:0 1rem}.markdown a.book-btn{display:inline-block;font-size:.875rem;color:var(--color-link);line-height:2rem;padding:0 1rem;border:1px solid var(--color-link);border-radius:.25rem;cursor:pointer}.markdown a.book-btn:hover{text-decoration:none}.markdown .book-hint.info{border-color:#6bf;background-color:rgba(102,187,255,.1)}.markdown .book-hint.warning{border-color:#fd6;background-color:rgba(255,221,102,.1)}.markdown .book-hint.danger{border-color:#f66;background-color:rgba(255,102,102,.1)}a del{opacity:.5}.kofi{display:block;text-align:center;margin-top:1rem}.author{display:block;margin-bottom:2rem}.logo-icon{transition:opacity .3s linear}.logo-icon--color,.author:hover .logo-icon--monochrome{opacity:0}.author:hover .logo-icon--color{opacity:1}.text-over path{stroke-dasharray:25;stroke-dashoffset:0;transition:stroke-dashoffset .5s linear}.author:hover .text-over path{stroke-dashoffset:25}.book-menu nav{max-width:calc(100vw - 2rem)}.book-toc .book-toc-inner nav{width:auto;padding:0;position:static;overflow-x:unset;overflow-y:unset}.book-toc-inner{width:16rem;padding:1rem;position:fixed;top:0;bottom:0;overflow-x:hidden;overflow-y:auto}@media screen and (min-width:80rem){.book-toc .book-toc-inner nav{padding:0}.book-toc-inner{padding:2rem 1rem}} -------------------------------------------------------------------------------- /content/docs/method-index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Method index 3 | summary: > 4 | Index of MockK methods and corresponding guidebook chapters. 5 | --- 6 | 7 | # Method index 8 | 9 | Index of MockK methods and corresponding guidebook chapters. 10 | 11 | ## Top level functions 12 | 13 | ### `mockk(...)` 14 | 15 | _Chapter: [Mocking](docs/mocking/)_ \ 16 | builds a regular mock 17 | 18 | ### `spyk()` 19 | 20 | _Chapter: [Spy on existing classes](docs/mocking/spy.md)_ \ 21 | builds a spy using the default constructor 22 | 23 | ### `spyk(obj)` 24 | 25 | _Chapter: [Spy on existing classes](docs/mocking/spy.md)_ \ 26 | builds a spy by copying from `obj` 27 | 28 | ### `slot` 29 | 30 | _Chapter: [Capture arguments to check later](docs/matching/capture.md)_ \ 31 | creates a capturing slot 32 | 33 | ### `every` 34 | 35 | _Chapter: [Stub out behaviour](docs/mocking/stubbing.md)_ \ 36 | starts a stubbing block 37 | 38 | ### `coEvery` 39 | 40 | _Chapter: [Coroutines and suspend functions](docs/mocking/coroutines.md)_ \ 41 | starts a stubbing block for coroutines 42 | 43 | ### `verify` 44 | 45 | _Chapter: [Verify that functions were called](docs/mocking/verify.md)_ \ 46 | starts a verification block 47 | 48 | ### `coVerify` 49 | 50 | _Chapter: [Coroutines and suspend functions](docs/mocking/coroutines.md)_ \ 51 | starts a verification block for coroutines 52 | 53 | ### `verifyAll` 54 | 55 | _Chapter: [Verify that functions were called](docs/mocking/verify.md#verifying-multiple-functions)_ \ 56 | starts a verification block that should include all calls 57 | 58 | ### `coVerifyAll` 59 | 60 | _Chapter: [Coroutines and suspend functions](docs/mocking/coroutines.md)_ \ 61 | starts a verification block that should include all calls for coroutines 62 | 63 | ### `verifyOrder` 64 | 65 | _Chapter: [Verify that functions were called](docs/mocking/verify.md#verifying-multiple-functions)_ \ 66 | starts a verification block that checks the order 67 | 68 | ### `coVerifyOrder` 69 | 70 | _Chapter: [Coroutines and suspend functions](docs/mocking/coroutines.md)_ \ 71 | starts a verification block that checks the order for coroutines 72 | 73 | ### `verifySequence` 74 | 75 | _Chapter: [Verify that functions were called](docs/mocking/verify.md#verifying-multiple-functions)_ \ 76 | starts a verification block that checks whether all calls were made in a specified sequence 77 | 78 | ### `coVerifySequence` 79 | 80 | _Chapter: [Coroutines and suspend functions](docs/mocking/coroutines.md)_ \ 81 | starts a verification block that checks whether all calls were made in a specified sequence for coroutines 82 | 83 | ### `excludeRecords` 84 | 85 | _Chapter: [Verify that functions were called](docs/mocking/verify.md#confirming-all-calls-were-verified)_ \ 86 | exclude some calls from being recorded 87 | 88 | ### `confirmVerified` 89 | 90 | _Chapter: [Verify that functions were called](docs/mocking/verify.md#confirming-all-calls-were-verified)_ \ 91 | confirms that all recorded calls were verified 92 | 93 | ### `clearMocks` 94 | 95 | _Chapter: [Clear state](docs/mocking/clear.md)_ \ 96 | clears specified mocks 97 | 98 | ### `registerInstanceFactory` 99 | 100 | _Chapter: TODO_ \ 101 | allows you to redefine the way of instantiation for certain object 102 | 103 | ### `mockkClass` 104 | 105 | _Chapter: TODO_ \ 106 | builds a regular mock by passing the class as parameter 107 | 108 | ### `mockkObject` 109 | 110 | _Chapter: [Mock singleton objects and static methods](docs/mocking/static.md#mocking-objects)_ \ 111 | makes an object an object mock or clears it if was already transformed 112 | 113 | ### `unmockkObject` 114 | 115 | _Chapter: [Mock singleton objects and static methods](docs/mocking/static.md#unmocking)_ \ 116 | makes an object mock back to a regular object 117 | 118 | ### `mockkStatic` 119 | 120 | _Chapter: [Mock singleton objects and static methods](docs/mocking/static.md#mocking-objects)_ \ 121 | makes a static mock out of a class or clears it if it was already transformed 122 | 123 | ### `unmockkStatic` 124 | 125 | _Chapter: [Mock singleton objects and static methods](docs/mocking/static.md#unmocking)_ \ 126 | makes a static mock back to a regular class 127 | 128 | ### `clearStaticMockk` 129 | 130 | _Chapter: TODO_ \ 131 | clears a static mock 132 | 133 | ### `mockkConstructor` 134 | 135 | _Chapter: [Mock constructors in code you don't own](docs/mocking/constructor.md)_ \ 136 | makes a constructor mock out of a class or clears it if it was already transformed 137 | 138 | ### `unmockkConstructor` 139 | 140 | _Chapter: [Mock constructors in code you don't own](docs/mocking/constructor.md#unmocking)_ \ 141 | makes a constructor mock back to a regular class 142 | 143 | ### `clearConstructorMockk` 144 | 145 | _Chapter: TODO_ \ 146 | clears the constructor mock 147 | 148 | ### `unmockkAll` 149 | 150 | _Chapter: TODO_ \ 151 | unmocks object, static and constructor mocks 152 | 153 | ### `clearAllMocks` 154 | 155 | _Chapter: TODO_ \ 156 | clears regular, object, static and constructor mocks 157 | 158 | ## Matchers 159 | 160 | By default, simple arguments are matched using `eq()`. 161 | 162 | ### `any()` 163 | 164 | _Chapter: [Allow any argument](docs/matching/any.md)_ \ 165 | matches any argument 166 | 167 | ### `allAny()` 168 | 169 | _Chapter: [Allow any argument](docs/matching/any.md)_ \ 170 | special matcher that uses `any()` instead of `eq()` for matchers that are provided as simple arguments 171 | 172 | ### `isNull()` 173 | 174 | _Chapter: TODO_ \ 175 | checks if the value is null 176 | 177 | ### `isNull(inverse=true)` 178 | 179 | _Chapter: TODO_ \ 180 | checks if the value is not null 181 | 182 | ### `ofType(type)` 183 | 184 | _Chapter: [Argument of a certain type](docs/matching/oftype.md)_ \ 185 | checks if the value belongs to the type 186 | 187 | ### `match { it.startsWith("string") }` 188 | 189 | _Chapter: TODO_ \ 190 | matches via the passed predicate 191 | 192 | ### `coMatch { it.startsWith("string") }` 193 | 194 | _Chapter: TODO_ \ 195 | matches via the passed coroutine predicate 196 | 197 | ### `matchNullable { it?.startsWith("string") }` 198 | 199 | _Chapter: TODO_ \ 200 | matches nullable value via the passed predicate 201 | 202 | ### `coMatchNullable { it?.startsWith("string") }` 203 | 204 | _Chapter: TODO_ \ 205 | matches nullable value via the passed coroutine predicate 206 | 207 | ### `eq(value)` 208 | 209 | _Chapter: [Check equality](docs/matching/equal.md)_ \ 210 | matches if the value is equal to the provided value via the `deepEquals` function 211 | 212 | ### `eq(value, inverse=true))` 213 | 214 | _Chapter: [Check equality](docs/matching/equal.md)_ \ 215 | matches if the value is not equal to the provided value via the `deepEquals` function 216 | 217 | ### `neq(value)` 218 | 219 | _Chapter: [Check equality](docs/matching/equal.md)_ \ 220 | matches if the value is not equal to the provided value via `deepEquals` function 221 | 222 | ### `refEq(value)` 223 | 224 | _Chapter: [Check equality](docs/matching/equal.md)_ \ 225 | matches if the value is equal to the provided value via reference comparison 226 | 227 | ### `refEq(value, inverse=true)` 228 | 229 | _Chapter: [Check equality](docs/matching/equal.md)_ \ 230 | matches if the value is not equal to the provided value via reference comparison 231 | 232 | ### `nrefEq(value)` 233 | 234 | _Chapter: [Check equality](docs/matching/equal.md)_ \ 235 | matches if the value is not equal to the provided value via reference comparison 236 | 237 | ### `cmpEq(value)` 238 | 239 | _Chapter: [Check equality](docs/matching/equal.md)_ \ 240 | matches if the value is equal to the provided value via the `compareTo` function 241 | 242 | ### `less(value)` 243 | 244 | _Chapter: [Comparables](docs/matching/compareto.md)_ \ 245 | matches if the value is less than the provided value via the `compareTo` function 246 | 247 | ### `more(value)` 248 | 249 | _Chapter: [Comparables](docs/matching/compareto.md)_ \ 250 | matches if the value is more than the provided value via the `compareTo` function 251 | 252 | ### `less(value, andEquals=true)` 253 | 254 | _Chapter: [Comparables](docs/matching/compareto.md)_ \ 255 | matches if the value is less than or equal to the provided value via the `compareTo` function 256 | 257 | ### `more(value, andEquals=true)` 258 | 259 | _Chapter: [Comparables](docs/matching/compareto.md)_ \ 260 | matches if the value is more than or equal to the provided value via the `compareTo` function 261 | 262 | ### `range(from, to, fromInclusive=true, toInclusive=true)` 263 | 264 | _Chapter: [Comparables](docs/matching/compareto.md)_ \ 265 | matches if the value is in range via the `compareTo` function 266 | 267 | ### `and(left, right)` 268 | 269 | _Chapter: [Combine matchers](docs/matching/combine.md)_ \ 270 | combines two matchers via a logical and 271 | 272 | ### `or(left, right)` 273 | 274 | _Chapter: [Combine matchers](docs/matching/combine.md)_ \ 275 | combines two matchers via a logical or 276 | 277 | ### `not(matcher)` 278 | 279 | _Chapter: [Combine matchers](docs/matching/combine.md)_ \ 280 | negates the matcher 281 | 282 | ### `capture(slot)` 283 | 284 | _Chapter: [Capture arguments to check later](docs/matching/capture.md)_ \ 285 | captures a value to a `CapturingSlot` 286 | 287 | ### `capture(mutableList)` 288 | 289 | _Chapter: [Capture arguments to check later](docs/matching/capture.md)_ \ 290 | captures a value to a list 291 | 292 | ### `captureNullable(mutableList)` 293 | 294 | _Chapter: [Capture arguments to check later](docs/matching/capture.md)_ \ 295 | captures a value to a list together with null values 296 | 297 | ### `captureLambda()` 298 | 299 | _Chapter: [Capture arguments to check later](docs/matching/capture.md)_ \ 300 | captures a lambda 301 | 302 | ### `captureCoroutine()` 303 | 304 | _Chapter: [Capture arguments to check later](docs/matching/capture.md)_ \ 305 | captures a coroutine 306 | 307 | ### `invoke(...)` 308 | 309 | _Chapter: TODO_ \ 310 | calls a matched argument 311 | 312 | ### `coInvoke(...)` 313 | 314 | _Chapter: TODO_ \ 315 | calls a matched argument for a coroutine 316 | 317 | ### `hint(cls)` 318 | 319 | _Chapter: TODO_ \ 320 | hints the next return type in case it's gotten erased 321 | 322 | ### `anyVararg()` 323 | 324 | _Chapter: TODO_ \ 325 | matches any elements in a vararg 326 | 327 | ### `varargAny(matcher)` 328 | 329 | _Chapter: TODO_ \ 330 | matches if any element is matching the matcher 331 | 332 | ### `varargAll(matcher)` 333 | 334 | _Chapter: TODO_ \ 335 | matches if all elements are matching the matcher 336 | 337 | ### `any...Vararg()` 338 | 339 | _Chapter: TODO_ \ 340 | matches any elements in vararg (specific to primitive type) 341 | 342 | ### `varargAny...(matcher)` 343 | 344 | _Chapter: TODO_ \ 345 | matches if any element is matching the matcher (specific to the primitive type) 346 | 347 | ### `varargAll...(matcher)` 348 | 349 | _Chapter: TODO_ \ 350 | matches if all elements are matching the matcher (specific to the primitive type) 351 | 352 | A few special matchers available in verification mode only: 353 | 354 | ### `withArg { code }` 355 | 356 | _Chapter: [Assertions with an argument](docs/matching/with.md)_ \ 357 | matches any value and allows to execute some code 358 | 359 | ### `withNullableArg { code }` 360 | 361 | _Chapter: [Assertions with an argument](docs/matching/with.md)_ \ 362 | matches any nullable value and allows to execute some code 363 | 364 | ### `coWithArg { code }` 365 | 366 | _Chapter: TODO_ \ 367 | matches any value and allows to execute some coroutine code 368 | 369 | ### `coWithNullableArg { code }` 370 | 371 | _Chapter: TODO_ \ 372 | matches any nullable value and allows to execute some coroutine code 373 | 374 | ## Validators 375 | 376 | ### `verify { mock.call() }` 377 | 378 | _Chapter: TODO_ \ 379 | Do unordered verification that a call was performed 380 | 381 | ### `verify(inverse=true) { mock.call() }` 382 | 383 | _Chapter: TODO_ \ 384 | Do unordered verification that a call was not performed 385 | 386 | ### `verify(atLeast=n) { mock.call() }` 387 | 388 | _Chapter: TODO_ \ 389 | Do unordered verification that a call was performed at least `n` times 390 | 391 | ### `verify(atMost=n) { mock.call() }` 392 | 393 | _Chapter: TODO_ \ 394 | Do unordered verification that a call was performed at most `n` times 395 | 396 | ### `verify(exactly=n) { mock.call() }` 397 | 398 | _Chapter: TODO_ \ 399 | Do unordered verification that a call was performed exactly `n` times 400 | 401 | ### `verifyAll { mock.call1(); mock.call2() }` 402 | 403 | _Chapter: TODO_ \ 404 | Do unordered verification that only the specified calls were executed for the mentioned mocks 405 | 406 | ### `verifyOrder { mock.call1(); mock.call2() }` 407 | 408 | _Chapter: TODO_ \ 409 | Do verification that the sequence of calls went one after another 410 | 411 | ### `verifySequence { mock.call1(); mock.call2() }` 412 | 413 | _Chapter: TODO_ \ 414 | Do verification that only the specified sequence of calls were executed for the mentioned mocks 415 | 416 | ### `verify { mock wasNot Called }` 417 | 418 | _Chapter: TODO_ \ 419 | Do verification that a mock was not called 420 | 421 | ### `verify { listOf(mock1, mock2) wasNot Called }` 422 | 423 | _Chapter: TODO_ \ 424 | Do verification that a list of mocks were not called 425 | 426 | ## Answers 427 | 428 | An Answer can be followed up by one or more additional answers. 429 | 430 | ### `returns value` 431 | 432 | _Chapter: TODO_ \ 433 | specify that the matched call returns a specified value 434 | 435 | ### `returnsMany list` 436 | 437 | _Chapter: TODO_ \ 438 | specify that the matched call returns a value from the list, with subsequent calls returning the next element 439 | 440 | ### `throws ex` 441 | 442 | _Chapter: TODO_ \ 443 | specify that the matched call throws an exception 444 | 445 | ### `answers { code }` 446 | 447 | _Chapter: TODO_ \ 448 | specify that the matched call answers with a code block scoped with `answer scope` 449 | 450 | ### `coAnswers { code }` 451 | 452 | _Chapter: TODO_ \ 453 | specify that the matched call answers with a coroutine code block with `answer scope` 454 | 455 | ### `answers answerObj` 456 | 457 | _Chapter: TODO_ \ 458 | specify that the matched call answers with an Answer object 459 | 460 | ### `answers { nothing }` 461 | 462 | _Chapter: TODO_ \ 463 | specify that the matched call answers null 464 | 465 | ### `just Runs` 466 | 467 | _Chapter: TODO_ \ 468 | specify that the matched call is returning Unit (returns null) 469 | 470 | ### `propertyType Class` 471 | 472 | _Chapter: TODO_ \ 473 | specify the type of backing field accessor 474 | 475 | ### `nullablePropertyType Class` 476 | 477 | _Chapter: TODO_ \ 478 | specify the type of backing field accessor as a nullable type 479 | 480 | ## Additional answer(s) 481 | 482 | A next answer is returned on each consequent call and the last value is persisted. 483 | So this is similar to the `returnsMany` semantics. 484 | 485 | ### `andThen value` 486 | 487 | _Chapter: TODO_ \ 488 | specify that the matched call returns one specified value 489 | 490 | ### `andThenMany list` 491 | 492 | _Chapter: TODO_ \ 493 | specify that the matched call returns value from the list, returning each time next element 494 | 495 | ### `andThenThrows ex` 496 | 497 | _Chapter: TODO_ \ 498 | specify that the matched call throws an exception 499 | 500 | ### `andThen { code }` 501 | 502 | _Chapter: TODO_ \ 503 | specify that the matched call answers with a code block scoped with `answer scope` 504 | 505 | ### `coAndThen { code }` 506 | 507 | _Chapter: TODO_ \ 508 | specify that the matched call answers with a coroutine code block with `answer scope` 509 | 510 | ### `andThenAnswer answerObj` 511 | 512 | _Chapter: TODO_ \ 513 | specify that the matched call answers with an Answer object 514 | 515 | ### `andThen { nothing }` 516 | 517 | _Chapter: TODO_ \ 518 | specify that the matched call answers null 519 | 520 | ## Answer scope 521 | 522 | ### `call` 523 | 524 | _Chapter: TODO_ \ 525 | a call object that consists of an invocation and a matcher 526 | 527 | ### `invocation` 528 | 529 | _Chapter: TODO_ \ 530 | contains information regarding the actual function invoked 531 | 532 | ### `matcher` 533 | 534 | _Chapter: TODO_ \ 535 | contains information regarding the matcher used to match the invocation 536 | 537 | ### `self` 538 | 539 | _Chapter: TODO_ \ 540 | reference to the object invocation made 541 | 542 | ### `method` 543 | 544 | _Chapter: TODO_ \ 545 | reference to the function invocation made 546 | 547 | ### `args` 548 | 549 | _Chapter: TODO_ \ 550 | reference to the arguments of invocation 551 | 552 | ### `nArgs` 553 | 554 | _Chapter: TODO_ \ 555 | number of invocation argument 556 | 557 | ### `arg(n)` 558 | 559 | _Chapter: TODO_ \ 560 | n-th argument 561 | 562 | ### `firstArg()` 563 | 564 | _Chapter: TODO_ \ 565 | first argument 566 | 567 | ### `secondArg()` 568 | 569 | _Chapter: TODO_ \ 570 | second argument 571 | 572 | ### `thirdArg()` 573 | 574 | _Chapter: TODO_ \ 575 | third argument 576 | 577 | ### `lastArg()` 578 | 579 | _Chapter: TODO_ \ 580 | last argument 581 | 582 | ### `captured()` 583 | 584 | _Chapter: TODO_ \ 585 | the last element in the list for convenience when capturing to a list 586 | 587 | ### `lambda<...>().invoke()` 588 | 589 | _Chapter: TODO_ \ 590 | call the captured lambda 591 | 592 | ### `coroutine<...>().coInvoke()` 593 | 594 | _Chapter: TODO_ \ 595 | call the captured coroutine 596 | 597 | ### `nothing` 598 | 599 | _Chapter: TODO_ \ 600 | null value for returning nothing as an answer 601 | 602 | ### `fieldValue` 603 | 604 | _Chapter: TODO_ \ 605 | accessor to the property backing field 606 | 607 | ### `fieldValueAny` 608 | 609 | _Chapter: TODO_ \ 610 | accessor to the property backing field with `Any?` type 611 | 612 | ### `value` 613 | 614 | _Chapter: TODO_ \ 615 | value being set casted to same type as the property backing field 616 | 617 | ### `valueAny` 618 | 619 | _Chapter: TODO_ \ 620 | value being set with `Any?` type 621 | 622 | ## Vararg scope 623 | 624 | ### `position` 625 | 626 | _Chapter: TODO_ \ 627 | the position of an argument in vararg array 628 | 629 | ### `nArgs` 630 | 631 | _Chapter: TODO_ \ 632 | overall count of arguments in vararg array 633 | -------------------------------------------------------------------------------- /static/favicon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/cover/mockk-bike-iso-transparent.svg: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------