MockSwift is a Mock library written in Swift.

Overview

MockSwift

Welcome to MockSwift

Release Build Status Codacy Badge Codacy Badge documentation Swift Package Manager compatible Swift license MIT

MockSwift allows you to write mocks and make better tests. Because MockSwift is an open source library 100% written in Swift, it is AVAILABLE ON ALL PLATFORMS.
Initially MockSwift is inspired by Mockito.

Table of Contents

Features

Actually MockSwift supports:

  • Stub
    • Protocol methods
    • Protocol properties
    • Protocol subscripts
    • Class
    • Struct
    • Enum
    • Default values for types
  • Verify interactions
    • Protocol methods
    • Protocol properties
    • Protocol subscripts
    • Class
    • Struct
    • Enum _ Parameter matching
    • Predicates
    • Generics

CHANGELOG

You can see all changes and new features here.

Installation

Swift Package Manager

MockSwift has been designed to work with Swift Package Manager.

// swift-tools-version:5.3

import PackageDescription

let package = Package(
  name: "MyProject",
  dependencies: [
    .package(url: "https://github.com/leoture/MockSwift.git", from: "1.0.0")
  ],
  targets: [
    .testTarget(name: "MyProjectTests", dependencies: ["MockSwift"])
  ]
)

Usage

Quick Look

class AwesomeTests: XCTestCase {

  private var printer: Printer!
  @Mock private var userService: UserService

  override func setUp() {
    printer = Printer(userService)
  }

  func test_sayHello() {
    // Given
    given(userService).fetchUserName(of: "you").willReturn("my friend")
    given(userService).isConnected.get.willReturn(true)
    given(userService)[cache: .any()].set(.any()).willDoNothing()

    // When
    let message = printer.sayHello(to: "you", from: "me")

    // Then
    then(userService).fetchUserName(of: .any()).called()
    then(userService).isConnected.get.called(times: 1)
    then(userService)[cache: "you"].set("my friend").calledOnce()
    
    XCTAssertEqual(message, "me: Hello my friend")
  }
}

Details

Suppose that you have a UserService protocol.

struct User: Equatable {
  let identifier: String
  let name: String
}

protocol UserService {
  func fetch(identifier: String) -> User
}

And you want to test this UserCore class.

class UserCore {
  private let service: UserService

  init(_ service: UserService) {
    self.service = service
  }

  func fetchCurrentUser() -> User {
    service.fetch(identifier: "current")
  }
}

Make better tests

Now, with MockSwift, you can use a mocked UserService in your tests with the @Mock annotation.

@Mock private var service: UserService

// equivalent to

private var service: UserService = Mock()

And easly configure it to fully test UseCore.

class UserCoreTests: XCTestCase {

  private var core: UserCore!
  @Mock private var service: UserService

  override func setUp() {
    core = UserCore(service)
  }

  func test_fetchCurrentUser() {
    // Given
    let expectedUser = User(identifier: "current", name: "John")

    given(service).fetch(identifier: .any()).willReturn(expectedUser)

    // When
    let user = core.fetchCurrentUser()

    // Then
    then(service).fetch(identifier: .any()).called()
    XCTAssertEqual(user, expectedUser)
  }
}

Given

given() enables you to define behaviours.
example:

given(service).fetch(identifier: .any()).willReturn(expectedUser)

// equivalent to

given(service) {
  $0.fetch(identifier: .any()).willReturn(expectedUser)
}
given(service) {
  $0.fetch(identifier: "current")
    .willReturn(expectedUser, expectedUser1, expectedUser2)

  $0.fetch(identifier: .match(when: \.isEmpty))
    .will { (params) -> User in
            // do something else
            return expectedUser
          }
}

you can also define behaviours when you instantiate the mock.

@Mock({
  $0.fetch(identifier: .any()).willReturn(expectedUser)
})
private var service: UserService

Then

then() enables you to verify calls.
example:

then(service).fetch(identifier: .any()).called()

// equivalent to

then(service) {
  $0.fetch(identifier: .any()).called()
}
then(service) {
  $0.fetch(identifier: "current").called(times: >=2)

  $0.fetch(identifier: == "").called(times: 0)
}

You can go further and verify order of calls

let assertion = then(service).fetch(identifier: "current").called(times: >=2)
then(service).fetch(identifier: == "").called(times: 1, after: assertion)

Stubs

In MockSwift, stubs are default values that are returned when no behaviours has been found.

Global Stubs

You can define a global stub for any type. It will concern all mocks you will use in every tests.

extension User: GlobalStub {
  static func stub() -> User {
    User(identifier: "id", name: "John")
  }
}

Local Stubs

You can also define a stub localy for any type. It will concern only the current mock.

@Mock(localStubs: [
      User.self => User(identifier: "id", name: "John")
])
private var service: UserService

Strategy

The default strategy is to find behaviour defined with given(). If no behaviour is found, it will return a local stub. If no local stub is found, it will return a global stub.

@Mock private var service: UserService

// equivalent to

@Mock(strategy: .default)
private var service: UserService

// equivalent to

@Mock(strategy: [.given, .localStubs, .globalStubs])
private var service: UserService

You can change the order of the strategy list or remove items as you want.

Write mocks

Automatically

MockSwift provides a stencil template for sourcery. You can use the AutoMockable annotation to generate code.

// sourcery: AutoMockable
protocol UserService {
  func fetch(identifier: String) -> User
}

To generate code at every build, you can add a build phase before Compile Sources.

sourcery \
--sources MyLibrary \
--templates MyLibraryTests/path/to/MockSwift.stencil \
--output MyLibraryTests/path/to/GeneratedMocks.swift \
--args module=MyLibrary

Manually

To enable MockSwift for UserService type, you have to extend Mock.

extension Mock: UserService where WrappedType == UserService {
  public func fetch(identifier: String) -> User {
    mocked(identifier)
  }
}

To allow behaviour definition through given() method, you have to extend Given.

extension Given where WrappedType == UserService {
  public func fetch(identifier: Predicate<String>) -> Mockable<User> {
    mockable(identifier)
  }
  public func fetch(identifier: String) -> Mockable<User> {
    mockable(identifier)
  }
}

To allow call verification through then() method, you have to extend Then.

extension Then where WrappedType == UserService {
  public func fetch(identifier: Predicate<String>) -> Verifiable<User> {
    verifiable(identifier)
  }
  public func fetch(identifier: String) -> Verifiable<User> {
    verifiable(identifier)
  }
}

Documentation

If you need more details about the API, you can check out our API documentation or our GitBook.

Contribution

Would you like to contribute to MockSwift? Please read our contributing guidelines and code of conduct.

License

MockSwift is released under the MIT license. See LICENSE for details.

Credits

Thanks to JetBrains

Comments
  • Compilation error in generated swift file when protocol have init method. How to use init in protocol?

    Compilation error in generated swift file when protocol have init method. How to use init in protocol?

    I have init method in my protocol. I am getting the below error when sourcery generates the code. Keyword 'init' cannot be used as an identifier here. If this name is unavoidable, use backticks to escape it

    ๐Ÿ“ For Example

    // sourcery: AutoMockable
    protocol DashboardRepository: AnyObject {
        func fetchDashBoard() -> [DashboardItem]
        func updateNotification()
        init(apiclient: APIClient)
    }
    

    Sourcery generated the code as below:

    public func init(apiclient: APIClient) -> DashboardRepository {
        mocked(apiclient)
      }
    .......
    

    ๐Ÿ“ What is the Question?

    How to generate the mock when protocol have init method?

    question 
    opened by mahabaleshwarhnr 2
  • Update tools versions

    Update tools versions

    โš ๏ธ IMPORTANT: Please do not create a Pull Request without creating an issue first. โš ๏ธ
    Please provide enough information so that others can review your pull request.
    REMOVE THIS SECTION


    opened by leoture 2
  • MockGiven willThrow

    MockGiven willThrow

    ๐Ÿš€ Describe the feature you'd like

    given(mock).function().willThrow(MyError())

    ๐Ÿ›  Describe the implementation you've considered

    A clear and concise description of any implementation solutions you've considered.

    โ„น๏ธ Other information
    enhancement 
    opened by leoture 2
  • Unable to get started with Mocking using MockSwift.

    Unable to get started with Mocking using MockSwift.

    I created a very simple protocol which I want to mock.

    protocol CalculatorServiceProtocol {
        func add(a: Int, b: Int) -> Int
    }
    
    

    In my test I write the following:

    final class when_user_performs_add_operation_using_calculator: XCTestCase {
    
        @Mock private var calculatorService: CalculatorServiceProtocol
        
        func test_should_add_successfully() {
           
            // expectation
            given(calculatorService).??? // how to call the add method and return value
            
            }
    }
    

    My confusion is that how do I call the add method on the CalculatorServiceProtocol. The .add method never shows up.

    question 
    opened by azamsharp 1
  • Always tag the version of an image explicitly

    Always tag the version of an image explicitly

    Codacy detected an issue:

    Message: Always tag the version of an image explicitly

    Occurred on:

    • Commit: 4c2a5fa531cbb40af39482ba86f2422f609b61cc
    • File: Dockerfile
    • LineNum: 1
    • Code: FROM kylef/swiftenv

    Currently on:

    • Commit: 7dac9f8116114c042f8822c1dc5e009bcbccf4bb
    • File: Dockerfile
    • LineNum: 1
    stale 
    opened by leoture 1
Releases(v1.1.0)
Owner
Jordhan Leoture
Mobile Developer
Jordhan Leoture
Mock Alamofire and URLSession requests without touching your code implementation

Mocker is a library written in Swift which makes it possible to mock data requests using a custom URLProtocol. Features Requirements Usage Activating

WeTransfer 898 Dec 26, 2022
A Popover that mock iOS SkinTone Selection Popover.

IMessage SkinTone Popover This is a popover mock the iOS iMessage Skin Tone Selection Menu (Popover) Features Long press to invoeke the popover, and t

Vincent Liu 1 Dec 9, 2021
A flexible mock server for automated and regression testing of iOS, Android and other apps.

Note: This document is intended as a quick introduction to Voodoo. As Voodoo has a large number of features, please refer to Voodoo's Github Wiki for

Derek Clarkson 7 Nov 23, 2022
This is a Swift port of Ruby's Faker library that generates fake data.

This is a Swift port of Ruby's Faker library that generates fake data. Are you still bothered with meaningless randomly character strings? Just relax

Vadym Markov 1.6k Jan 3, 2023
PinpointKit is an open-source iOS library in Swift that lets your testers and users send feedback with annotated screenshots using a simple gesture.

PinpointKit is an open-source iOS library in Swift that lets your testers and users send feedback with annotated screenshots using a simple gesture. F

Lickability 1.1k Jan 6, 2023
The XCTest Project, A Swift core library for providing unit test support

XCTest The XCTest library is designed to provide a common framework for writing unit tests in Swift, for Swift packages and applications. This version

Apple 1k Jan 4, 2023
An elegant library for stubbing HTTP requests with ease in Swift

Mockingjay An elegant library for stubbing HTTP requests in Swift, allowing you to stub any HTTP/HTTPS using NSURLConnection or NSURLSession. That inc

Kyle Fuller 1.5k Dec 3, 2022
Test Library for Swift's Error Handling

CatchingFire CatchingFire is a Swift test framework, which helps making expectations against the error handling of your code. It provides for this pur

Marius Rackwitz 75 May 16, 2022
Lightweight touch visualization library in Swift. A single line of code and visualize your touches!

TouchVisualizer is a lightweight pure Swift implementation for visualising touches on the screen. Features Works with just a single line of code! Supp

Morita Naoki 851 Dec 17, 2022
A Swift test double library. Guava - looks like an apple but it's not.

Guava Guava helps you to make your unit tests more flexible. It allows you to replace parts of your system under test with a test double objects. Tabl

Denis Chagin 10 Mar 22, 2022
Freezer is a library that allows your Swift tests to travel through time by mocking NSDate class.

Freezer Freezer is a library that allows your Swift tests to travel through time by mocking NSDate class. Usage Once Freezer.start() has been invoked,

Sergey Petrov 8 Sep 24, 2022
Trust - Swift DCI Test Library

Trust Swift - DCI Pattern Test Library Support SPM How to use ? struct User {

gitaek lee 1 Feb 13, 2022
SwiftCheck is a testing library that automatically generates random data for testing of program properties

SwiftCheck QuickCheck for Swift. For those already familiar with the Haskell library, check out the source. For everybody else, see the Tutorial Playg

TypeLift 1.4k Dec 21, 2022
ShortWebCore - This iOS library lets you run automations on Web Views.

This iOS library lets you run automations on Web Views. Example (Optional) Declare class conforming to AutomationRunnerDelegate: import S

Emma Cold 19 Dec 26, 2022
Library for unifying the approach to network mocking in iOS unit- & UI-tests.

TinkoffMockStrapping Example To run the example project, clone the repo, and run pod install from the Example directory first. Requirements Installati

Online financial ecosystem 22 Jan 3, 2023
A simple and lightweight matching library for XCTest framework.

Match A simple and lightweight matching library for XCTest framework. Getting started Swift Package Manager You can add Match to your project by addin

Michaล‚ Tynior 6 Oct 23, 2022
A Mac and iOS Playgrounds Unit Testing library based on Nimble.

Spry Spry is a Swift Playgrounds Unit Testing library based on Nimble. The best thing about Spry is that the API matches Nimble perfectly. Which means

Quick 327 Jul 24, 2022
Small library to easily run your tests directly within a Playground

[] (https://developer.apple.com/swift/) Build Status Branch Status master develop About PlaygroundTDD enables you to use TDD directly on Xcode Playgro

Whiskerz AB 317 Nov 22, 2022
AppiumLibrary is an appium testing library for RobotFramework

Appium library for RobotFramework Introduction AppiumLibrary is an appium testing library for Robot Framework. Library can be downloaded from PyPI. It

Serhat Bolsu 327 Dec 25, 2022