All Projects → pirishd → InstantMock

pirishd / InstantMock

Licence: MIT license
Create mocks easily in Swift

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to InstantMock

Cuckoo
Boilerplate-free mocking framework for Swift!
Stars: ✭ 1,344 (+1427.27%)
Mutual labels:  mock, unit-testing, stub
Hippolyte
HTTP Stubbing in Swift
Stars: ✭ 109 (+23.86%)
Mutual labels:  mock, stub, swift5
Mocktopus
Mocking framework for Rust
Stars: ✭ 179 (+103.41%)
Mutual labels:  mock, unit-testing
Sinon Jest Cheatsheet
Some examples on how to achieve the same goal with either of both libraries: sinon and jest. Also some of those goals achievable only by one of these tools.
Stars: ✭ 226 (+156.82%)
Mutual labels:  mock, unit-testing
babel-plugin-rewire-exports
Babel plugin for stubbing [ES6, ES2015] module exports
Stars: ✭ 62 (-29.55%)
Mutual labels:  unit-testing, stub
Mockit
A tool to quickly mock out end points, setup delays and more...
Stars: ✭ 1,534 (+1643.18%)
Mutual labels:  mock, stub
Spy
Clojure/ClojureScript library for stubs, spies and mocks.
Stars: ✭ 131 (+48.86%)
Mutual labels:  mock, stub
aem-stubs
Tool for providing sample data for AEM applications in a simple and flexible way. Stubbing server on AEM, no separate needed.
Stars: ✭ 40 (-54.55%)
Mutual labels:  mock, stub
Impersonator
Ruby library to record and replay object interactions
Stars: ✭ 100 (+13.64%)
Mutual labels:  mock, stub
sinon-mongoose
Extend Sinon stubs for Mongoose methods to test chained methods easily
Stars: ✭ 87 (-1.14%)
Mutual labels:  mock, stub
entity-framework-mock
Easy Mock wrapper for mocking EF6 DbContext and DbSet using Moq or NSubstitute
Stars: ✭ 45 (-48.86%)
Mutual labels:  mock, unit-testing
FireMock
Mock and stub HTTP requests. Test your apps with fake data and files responses.
Stars: ✭ 25 (-71.59%)
Mutual labels:  mock, stub
Mockery
Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL).
Stars: ✭ 10,048 (+11318.18%)
Mutual labels:  mock, stub
Mimic
A mocking library for Elixir
Stars: ✭ 104 (+18.18%)
Mutual labels:  mock, stub
Mockingbird
Simplify software testing, by easily mocking any system using HTTP/HTTPS, allowing a team to test and develop against a service that is not complete or is unstable or just to reproduce planned/edge cases.
Stars: ✭ 149 (+69.32%)
Mutual labels:  mock, stub
Unit Threaded
Advanced unit test framework for D
Stars: ✭ 100 (+13.64%)
Mutual labels:  mock, unit-testing
mocka
Mocka - The complete testing framework for LUA and Nginx
Stars: ✭ 26 (-70.45%)
Mutual labels:  mock, stub
Timex
A test-friendly replacement for golang's time package
Stars: ✭ 53 (-39.77%)
Mutual labels:  mock, stub
umock-c
A pure C mocking library
Stars: ✭ 29 (-67.05%)
Mutual labels:  mock, unit-testing
ts-mock-imports
Intuitive mocking library for Typescript class imports
Stars: ✭ 103 (+17.05%)
Mutual labels:  mock, stub

InstantMock

Create Mocks Easily in Swift

Build Status codecov.io CocoaPods Plattforms CocoaPods Version

InstantMock aims at creating mocks easily in Swift, and configuring them with expectations or stubbed implementations.

For examples, see Example.playground.

Swift versions compatibility:

Swift version InstantMock version
5.0 2.5.X
4.2 2.2.X
4.0 2.0/2.1
3.X 1.1.X

How to Create a Mock?

InstantMock enables to create a single mock that can be used in many tests, for a protocol or a class.

For a Protocol

The easiest way to create a mock for a protocol is to inherit from the Mock class.

// MARK: Protocol to be mocked
protocol Foo {
    func bar(arg1: String, arg2: Int) -> Bool
}

// MARK: Mock class inherits from `Mock` and adopts the `Foo` protocol
class FooMock: Mock, Foo {

    // implement `bar` of the `Foo` protocol
    func bar(arg1: String, arg2: Int) -> Bool {
        return super.call(arg1, arg2)! // provide values to parent class
    }

}

For a Class

To create a mock for a class, the mock must adopt the MockDelegate protocol.

// MARK: Class to be mocked
class Foo {
    func bar(arg1: String, arg2: Int) -> Bool
}

// MARK: Mock class inherits from `Foo` and adopts the `MockDelegate` protocol
class FooMock: Foo, MockDelegate {

    // create `Mock` delegate instance
    private let mock = Mock()

    // conform to the `MockDelegate` protocol, by providing the `Mock` instance
    var it: Mock {
        return mock
    }

    // implement `bar` of the `Foo` class
    override func bar(arg1: String, arg2: Int) -> Bool {
        return mock.call(arg1, arg2)! // provide values to the delegate
    }

}

Rules

To work properly, mocks must comply with a few rules regarding return values, due to Swift strong typing.

Optional Return Value

The syntax is as follow:

func returnsOptional() -> Bool? {
    return mock.call()
}

Here, call() returns nil or Void.

Non-Optional Return Value

For some methods, mocks must return non-optional values. If a return value type adopts the MockUsable protocol (which is the case for the most common types like Bool, Int…), just force unwrapping the result to call(), like in the following example:

func returnsMockUsable() -> Bool { // `Bool` adopts `MockUsable`
    return mock.call()! // force unwrapping
}

For other types, make sure to provide a default value, like in the following example:

func returnsCustom() -> CustomType {
    return mock.call() ?? CustomType() // return a `CustomType` default value
}

Throwing

For catching errors on throwing methods, simply use callThrowing() instead of call().

If a return value type adopts the MockUsable protocol (which is the case for the most common types like Bool, Int…), just force unwrapping the result to callThrowing(), like in the following example:

func bazMockUsable() throws -> Bool {
    return try callThrowing()!
}

For other types, make sure to provide a default value, like in the following example:

func bazCustom() throws -> CustomType {
    return try callThrowing() ?? CustomType() // return a `CustomType` default value
}

Properties

It is possible to mock properties declared in a protocol, like in the following example:

// define protocol with a property `prop` that has a getter and a setter
protocol FooProperty {
    var prop: String { get set }
}

// mock of `FooProperty`
class FooPropertyMock: Mock, FooProperty {
    var prop: String {
        get { return super.call()! }
        set { return super.call(newValue) }
    }
}

How to Set Expectations?

Expectations aim at verifying that a call is done with some arguments. They are set using a syntax like in the following example:

// create mock instance
let mock = FooMock()

// create expectation on `mock`, that is verified when `bar` is called
// with "hello" for `arg1` and any value of the type of `arg2`
mock.expect().call(
    mock.bar(arg1: Arg.eq("hello"), arg2: Arg.any())
)

Reject

Rejections are the contrary of expectations. They make sure no call is being done with some arguments. Simply use reject() instead of expect().

Number of calls

In addition, expectations and rejections can be set on the number of calls: Use the following syntax:

// create expectation on `mock`, that is verified when 2 calls are done on `bar`
// with "hello" for `arg1` and any value of the type of `arg2`
mock.expect().call(
    mock.bar(arg1: Arg.eq("hello"), arg2: Arg.any()),
    count: 2
)

Properties

Setting expectations on properties can be done using the following syntax:

// create mock instance
let mock = FooPropertyMock()

// create expectation on `mock`, that is verified when the property `prop` is called
mock.expect().call(mock.prop)

// create expectation on `mock`, that is verified when the property `prop` is set
// with the exact value "hello"
mock.expect().call(
    mock.property.set(mock.prop, value: Arg.eq("hello"))
)

Verifications

Verifying expectations and rejections is done this way:

// test fails when any of the expectations or rejections set on `mock` is not verified
mock.verify()

Reset Expectations

Expecations can be reset this way:

mock.resetExpectations()

How to Stub Calls?

Stubs aim at performing actions when a function is called with some arguments. They are set using a syntax like in the following example:

// create mock instance
let mock = FooMock()

// create stubbed implementation of the `bar` method, which returns `true` when called
// with "hello" for `arg1` and any value of the type of `arg2`
mock.stub().call(
    mock.bar(arg1: Arg.eq("hello"), arg2: Arg.any())
).andReturn(true)

Return Value

Set the return value with andReturn(…) on the stub instance.

Compute a Return Value

This is done with andReturn(closure: { _ in return … }) on the stub instance. This enables to return different values on the same stub, depending on some conditions.

Call Another Function

This is done with andDo { _ in … } on the stub instance.

Throw an Error

This is done with andThrow(…) on the stub instance.

Chaining

Chaining several actions on the same stub is possible, given they don't confict. For example, it is possible to return a value and call another function, like in andReturn(true).andDo { _ in print("something") }.

Rules:

  • the last closure registered by andDo is called first
  • the last error registered by andThrow is thrown
  • the last return value registered by andReturn is returned
  • otherwise, the last return value computation method, registered by andReturn(closure:), is called

Reset Stubs

Stubs can be reset this way:

mock.resetStubs()

Example:

// configure mock to return "string" when calling `basic` whatever provided arguments
mock.stub().call(mock.basic(arg1: Arg.any(), arg2: Arg.any())).andReturn("string")

// reset the previously configured stubs
mock.resetStubs()

// calling `basic` does not return "string"
let ret = mock.basic(arg1: "", arg2: 2)
XCTAssertNotEqual(ret, "string")

Argument Matching

Expectations are verified only if arguments match what is registered. Same goes for calling stubbed implementations.

Exact Value

Matching an exact value is done with Arg.eq(…).

Values can be matched if they:

  • conform to the AnyObject protocol, which is the case for all classes implicitly, for example Arg.eq(NSString("hello"))
  • or conform to the MockUsable protocol, for example Arg.eq(42)
  • or they are types, for example Arg.eq(String.self)
  • or they are tuples, limited to 5 values, for example Arg.eq(("a string", 42))

Any Value

Matching any value can be done for types that adopt the MockUsable protocol, with Arg.any().

Certain Condition

Matching a value that verifies a certain condition is done with Arg.verify({ _ in return … }).

Closure

Matching a closure is a special case. Use the following syntax: Arg.closure().

Limitation: closures can be matched as long as they have less than 5 arguments.

Argument Capturing

Arguments can also be captured for later use thanks to the ArgumentCaptor class.

For example:

// create captor for type `String`
let captor = ArgumentCaptor<String>()

// create expectation on `mock`, that is verified when `bar` is called
// with 42 for `arg2`. All values for `arg1` are captured.
mock.expect().call(mock.bar(arg1: captor.capture(), arg2: Arg.eq(42)))
...

// retrieve the last captured value
let value = captor.value

// retrieve all captured values
let values = captor.allValues

Capturing a Closure

Capturing a closure is particularly useful for stubbing the behavior of a method with callbacks, see this conversation.

Capturing a closure is a special case. Use the following syntax:

Limitation: closures can be captured as long as they have less than 5 arguments.

// create captor for type closure `(Int) -> Bool`
let captor = ArgumentClosureCaptor<(Int) -> Bool>()
...
// retrieve the last captured closure, and call it
let ret = captor.value!(42)

MockUsable

MockUsable is a protocol that makes types easily usable in mocks. For a given type, it allows to return non-optional values and to match any values.

Adding MockUsable on an existing type is done by creating an extension that adopts the protocol. For example:

extension SomeClass: MockUsable {

    static var any = SomeClass() // any value

    // return any value
    public static var anyValue: MockUsable {
        return SomeClass.any
    }

    // returns true if an object is equal to another `MockUsable` object
    public func equal(to value: MockUsable?) -> Bool {
        guard let value = value as? SomeClass else { return false }
        return self == value
    }

}

Adding MockUsable on an existing type that uses inheritance, should always be done on the deepest subclass. Indeed, adding this extension to both a parent and a subclass would create build conflicts.

Supported Types

For now, the following types are MockUsable:

  • Bool
  • Int, Int64
  • UInt, UInt64
  • Float
  • Double
  • String
  • Set
  • Array
  • Dictionary
  • Date

Changelog

List of changes can be found here.

Requirements

  • Xcode 10
  • iOS 9
  • osX 10.10

Installation

Cocoapods

InstantMock is available using CocoaPods, see Podfile example:

target 'Example' do

    # Tests target
    target 'ExampleTests' do
        inherit! :search_paths
        pod 'InstantMock'
    end

end

Swift Package Manager

InstantMock is available using the Swift Package Manager, by adding the dependency either with Xcode or by editing the Package.swift file:

.package(url: "https://github.com/pirishd/InstantMock", from: "2.5.6"),

Inspiration

Author

Patrick Irlande - [email protected]

License

InstantMock is available under the MIT License.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].