{"id":26072768,"url":"https://github.com/danielr/mokka","last_synced_at":"2025-04-11T20:33:07.854Z","repository":{"id":62447963,"uuid":"189602051","full_name":"danielr/Mokka","owner":"danielr","description":"A collection of helpers to make it easier to write testing mocks in Swift.","archived":false,"fork":false,"pushed_at":"2019-07-11T08:42:57.000Z","size":149,"stargazers_count":5,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-10T13:07:31.005Z","etag":null,"topics":["mock","mocking","mocking-utility","stub","stubbing","swift","unit-testing"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/danielr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-31T13:52:58.000Z","updated_at":"2023-05-04T14:57:43.000Z","dependencies_parsed_at":"2022-11-01T22:30:22.794Z","dependency_job_id":null,"html_url":"https://github.com/danielr/Mokka","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielr%2FMokka","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielr%2FMokka/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielr%2FMokka/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielr%2FMokka/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danielr","download_url":"https://codeload.github.com/danielr/Mokka/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248476710,"owners_count":21110343,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mock","mocking","mocking-utility","stub","stubbing","swift","unit-testing"],"created_at":"2025-03-09T00:42:57.778Z","updated_at":"2025-04-11T20:33:07.817Z","avatar_url":"https://github.com/danielr.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003cimg src=\"Mokka_logo.png\" width=\"600” max-width=\"90%\" alt=\"Mokka\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\t\u003ca href=\"https://app.bitrise.io/app/1b64319566421dbf\"\u003e\u003cimg src=\"https://img.shields.io/bitrise/1b64319566421dbf/master.svg?token=aK7YocCEHyQlNQ9l43nE3g\" alt=\"Bitrise build status\" /\u003e\u003c/a\u003e\n\t\u003ca href=\"https://codecov.io/gh/danielr/Mokka\"\u003e\u003cimg src=\"https://img.shields.io/codecov/c/github/danielr/Mokka.svg\" alt=\"Code coverage\" /\u003e\u003c/a\u003e\n\t\u003ca href=\"https://cocoapods.org/pods/Mokka\"\u003e\u003cimg src=\"https://img.shields.io/cocoapods/v/Mokka.svg\" alt=\"CocoaPods\" /\u003e\u003c/a\u003e\n\t\u003cimg src=\"https://img.shields.io/badge/swift-5.0-DE5C43.svg\" alt=\"Swift Version\" /\u003e\n\t\u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-lightgrey.svg\" alt=\"License\" /\u003e\u003c/a\u003e\n\t\u003ca href=\"http://twitter.com/danielrinser\"\u003e\u003cimg src=\"https://img.shields.io/badge/twitter-@danielrinser-blue.svg\" alt=\"Twitter\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003ch3 align=\"center\"\u003e\n\tA collection of helpers to make it easier to write testing mocks in Swift.\n\u003c/h3\u003e\n\n\n## Motivation\nDue to Swift's very static nature, mocking and stubbing is much harder to do than in other languages. There are no dynamic mocking framework like `OCMock` or `Mockito`. The usual approach is to just write your mock objects manually, like so:\n\n```swift\nprotocol Foo {\n    func doSomething(arg: String) -\u003e Int\n}\n\nclass FooMock: Foo {\n    var doSomethingHasBeenCalled = false\n    var doSomethingArgument = String?\n    var doSomethingReturnValue: Int!\n\n    func doSomething(arg: String) -\u003e Int {\n        doSomethingHasBeenCalled = true\n        doSomethingArgument = arg\n        return doSomethingReturnValue\n    }\n}\n```\n\nThis is a lot of boilerplate (and this is just a simple example, which doesn't allow for conditional stubbing, for example). This is where Mokka comes in.\n\n\n## Overview\n\nMokka provides a testing helper class called `FunctionMock\u003cArgs\u003e` (and a variant for returning functions called `ReturningFunctionMock\u003cArgs, ReturnValue\u003e`) that takes care of:\n\n* Recording function/method calls for verification (*Has the method been called?*, *How often has the method been called?*)\n* Capturing the arguments for verification (*With which arguments has the method been called?*)\n* Stubbing return values (also conditionally) (*This method should return `42` if called with argument `\"x\"`*)\n\nWith these helpers it gets much more convenient to define your mock objects:\n\n```swift\nclass FooMock: Foo {\n    let doSomethingFunc = ReturningFunctionMock\u003cString, Int\u003e()\n    func doSomething(arg: String) -\u003e Int {\n        return doSomethingFunc.recordCallAndReturn(arg)\n    }\n}\n```\n\nYou can now use the function mock object for verification:\n\n```swift\nfunc testSomething() {\n    // ...\n    XCTAssertEqual(myMock.doSomethingFunc.callCount, 2)\n    XCTAssertEqual(myMock.doSomethingFunc.argument, \"lorem ipsum\")\n    // ...\n}\n```\n\nand for faking the return value:\n\n```swift\nfunc testSomething() {\n    // static return value\n    myMock.doSomethingFunc.returns(100)\n\n    // dynamic return value\n    myMock.doSomethingFunc.returns { $0 + 200 }   // $0 is the argument(s) passed to the method\n\n    // conditional return value\n    myMock.doSomethingFunc.returns(123, when: { $0 == \"foo\" })\n    myMock.doSomethingFunc.returns(456, when: { $0 == \"bar\" })\n    myMock.doSomethingFunc.returns(789)\n}\n```\n\n## Requirements\n\n* Xcode 10.2\n* Swift 5.0\n\n## Installation\n\n### CocoaPods\n\nTo install Mokka via CocoaPods, just add the `Mokka` pod for your **test target** to the Podfile:\n\n```ruby\npod 'Mokka'\n```\n\n### Swift Package Manager\n\nYou can install Mokka using Swift Package Manager. Just add this repository as a dependency to your `Package.swift` file (and don't forget to also add `\"Mokka\"` as a dependency in your test target):\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/danielr/Mokka\", from: \"1.0.0\")\n    // ...\n]\n```\n\n### Carthage\n\nTo install Mokka with Carthage, add this to your Cartfile:\n\n```\ngithub \"danielr/Mokka\"\n```\n\nThen drag the built `Mokka.framework` to your project and make sure it's [added to the unit test target](https://github.com/Carthage/Carthage#adding-frameworks-to-unit-tests-or-a-framework), not the main app target. If you see issues errors like \"The bundle xxx couldn’t be loaded because it is damaged or missing necessary resources.\", then you [might need to tweak your test target's **Runtime Search Paths**](https://github.com/Carthage/Carthage/issues/1002).\n\n## Documentation\n\n### Types of mocks\n\nThere are currently three types of mock helpers available:\n\n* **`FunctionMock`:** Allows to record the calls to a function (the call count and the arguments), as well as to optionally stub the function's behavior. Use this for functions that have a `Void` return value.\n* **`ReturningFunctionMock`:** Provides the same functionality as `FunctionMock`, but adds the ability to fake the returned value. Use this for functions that have a non-void return value.\n* **`PropertyMock`:** Allows to provide fake values for a property and record whether a property has been read or set.\n\n### How to implement your mocks\n\nThe first step is to implement your mocks using Mokka's helpers.\nThe general approach is the same for all types of mocks: You declare a property for the mock and use that mock object inside your function implementations to record the calls to that function.\n\nFor the examples below, let's assume we want to mock the following protocol:\n\n```swift\nprotocol Engine {\n    func turnOn()\n    func turnOff()\n    var isOn: Bool { get }\n\n    func setSpeed(to value: Float)  // kilometers per hour\n    func setSpeed(to value: Float, in unit: UnitSpeed)\n\n    func currentSpeed(in unit: UnitSpeed) -\u003e Double\n}\n```\n\n#### Functions without return value\n\nFor functions that don't return a value, use `FunctionMock\u003cArgs\u003e`. This class has one generic parameter which defines the type(s) of the argument(s).\n\nFor functions with **no arguments**, that should be `Void`:\n\n```swift\nclass EngineMock: Engine {\n    let turnOnFunc = FunctionMock\u003cVoid\u003e(name: \"turnOn()\")\n    func turnOn() {\n        turnOnFunc.recordCall()\n    }\n\t\n    // ...\n}\n```\n\n*Note: The `name` parameter in the mock initializers is optional. It is purely informational and might be useful for error messages (e.g. better assertion error messages). It is good practice to provide the names in the standard Swift #selector syntax.*\n\nFor functions with a **single argument**, just use that argument's type:\n\n```swift\nclass EngineMock: Engine {\n    let setSpeedFunc = FunctionMock\u003cFloat\u003e(name: \"setSpeed(to:)\")\n    func setSpeed(to value: Float) {\n        setSpeedFunc.recordCall(value)\n    }\n\t\n    // ...\n}\n```\n\nFor functions with **more than one argument**, you need to use a tuple to represent the arguments (because Swift does not ([yet?](https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#variadic-generics)) support variadic generic parameters). Although you don't have to, it is a good practice to name the tuple elements, which makes it much clearer when referring to them in your testing code.\n\n```swift\nclass EngineMock: Engine {\n    let setSpeedInUnitFunc = FunctionMock\u003c(value: Float, unit: UnitSpeed)\u003e(name: \"setSpeed(to:unit:)\")\n    func setSpeed(to value: Float, in unit: UnitSpeed) {\n        setSpeedInUnitFunc.recordCall((value: value, unit: unit))\n    }\n\t\n    // ...\n}\n```\n\n\n#### Functions with return value\n\nFor functions with a return value, use `ReturningFunctionMock\u003cArgs, ReturnValue\u003e`. This works very much the same way as `FunctionMock`, but adds a second generic parameter for the return value type. It also provides a `recordCallAndReturn()` method, instead of the `recordCall()` method.\n\n```swift\nclass EngineMock: Engine {\n    let currentSpeedFunc = ReturningFunctionMock\u003cUnitSpeed, Double\u003e(name: \"currentSpeed(in:)\")\n    func currentSpeed(in unit: UnitSpeed) -\u003e Double {\n        return currentSpeedFunc.recordCallAndReturn(unit)\n    }\n\t\n    // ...\n}\n```\n\nFor the arguments of returning methods, the same rules apply as for non-returning functions (see above). For example:\n\n* A mock for a function that has no arguments and returns a Bool would be declared as `ReturningFunctionMock\u003cVoid, Bool\u003e`\n* A mock for a function that has two arguments of type `Int` and `String?` and returns a `Double` would be declared as `ReturningFunctionMock\u003c(arg1: Int, arg2: String?), Double\u003e`\n\n\n#### Properties\n\nIn many cases it is enough to just implement property requirements of the mocked protocol by declaring a stored property with a default value in your mock. However, when you want to be able to explicitly track whether a property has been read or written, Mokka's `PropertyMock` can be helpful. It is generic over the type of the property and its use in the mock implementation is quite self-explanatory: Instead of using a stored property, declare a computed property and delegate the getter and setter (if it's settable property) to the `get()` and `set(_:)` methods of the `PropertyMock` object:\n\n```swift\nclass EngineMock: Engine {\n    let isOnProperty = PropertyMock\u003cBool\u003e(name: \"isOn\")\n    var isOn: Bool {\n        get { return isOnProperty.get() }\n        set { isOnProperty.set(newValue) }\n    }\n\t\n    // ...\n}\n```\n\nNote that you don't need to provide a default value for the property (the `get()` method fails with a `preconditionFailure` if there is no value).\n\n\n### Call count verification\n\nA common use case for mocks is to verify if a method has been called, and sometimes specifically how often it has been called. For that, both `FunctionMock` and `ReturningFunctionMock` provide some properties:\n\n* `called: Bool` Returns whether the method has been called (once or more).\n* `calledOnce: Bool` Returns whether the method has been called exactly once.\n* `callCount: Int` The number of times the method has been called.\n\n```swift\nXCTAssertTrue(engineMock.setSpeedFunc.called)\nXCTAssertTrue(engineMock.setSpeedFunc.calledOnce)\nXCTAssertEqual(engineMock.setSpeedFunc.callCount, 3)\n```\n\n### Argument verification\n\nIn addition to verifying if a function has been called, you often also want to check the argument(s) with which the function has been called. You can do that via the `arguments` property:\n\n```swift\nXCTAssertEqual(engineMock.setSpeedInUnitFunc.arguments.value, 100.0)\nXCTAssertEqual(engineMock.setSpeedInUnitFunc.arguments.unit, .kilometersPerHour)\n```\n\n(This requires that you follow the recommended practice of naming the tuple members, see above. If you don't, you have to access the arguments by their index, e.g. `arguments.0`.)\n\n\nFor single-argument functions (where there's no arguments tuple) you can also use the `argument` property, which looks a bit nicer:\n\n```swift\nXCTAssertEqual(engineMock.setSpeedFunc.argument, 100.0)\n```\n\n### Stubbing\n\nSometimes it's necessary to stub the behavior of a function, for example to introduce some important side-effects. One common example for this is calling a delegate method. You can do that by providing a closure that will be executed when the function is called. The closure will be provided with the function arguments:\n\n```swift\nlet delegate = FooDelegateMock()\nsomeMock.myFunction.stub { arg in\n    delegate.somethingHappened(with: arg)\n}\n```\n\n### Faking the return value\n\nFor returning functions it's crucial to be able to fake the return value. Mokka provides 3 ways of doing that: Static return values, dynamic return values and conditional return values. Let's have a look at each of those.\n\n#### Providing a static return value\n\nFor most cases it's sufficient to provide a simple static value that should be returned by the mock implementation:\n\n```swift\nengineMock.currentSpeedFunc.returns(100.0)\n```\n\n#### Providing a return value dynamically\n\nSometimes it's convenient to provide a return value that is dynamically generated, often depending on the function's arguments. You can do that by providing a closure: \n\n```swift\nengineMock.currentSpeedFunc.returns { unit in\n    // always return 100 km/h, converted to the requested target unit\n    let kmhValue = Measurement(value: 100, unit: UnitSpeed.kilometersPerHour)\n    return kmhValue.converted(to: unit).value\n}\n```\n\n#### Providing return values conditionally\n\nBoth, static and dynamic return values can also be provided conditionally:\n\n```swift\nengineMock.currentSpeedFunc.returns(100.00, when: { $0 == .kilometersPerHour })\nengineMock.currentSpeedFunc.returns(62.137, when: { $0 == .milesPerHour })\nengineMock.currentSpeedFunc.returns(0)\t   // otherwise\n```\n\n### Mocking properties\n\nThis is how you use properties that are backed by `PropertyMock` in your testing code:\n\n```swift\nsomeMock.fooProperty.value = 10\t// use value to access the underlying property value\n\n// do something\n\nXCTAssertTrue(someMock.fooProperty.hasBeenRead)\nXCTAssertFalse(someMock.fooProperty.hasBeenSet\n```\n\n## Example\n\nYou can find a simple example project in [MokkaExample](MokkaExample/).\n\nIt includes\n\n* a subject under test (`Car`)\n* two mocked protocols (`Engine` and `Battery`)\n\nIt is a minimal example, but it should be enough to get you started with the concepts of Mokka.\n\n## Author\n\nMokka has been created and is maintained by Daniel Rinser, [@danielrinser](https://twitter.com/danielrinser).\n\n## License\n\nMokka is available under the [MIT License](https://github.com/danielr/Mokka/blob/master/LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielr%2Fmokka","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanielr%2Fmokka","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielr%2Fmokka/lists"}