Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/leoture/MockSwift
MockSwift is a Mock library written in Swift.
https://github.com/leoture/MockSwift
mock playground swift swift-package-manager test xcode
Last synced: about 2 months ago
JSON representation
MockSwift is a Mock library written in Swift.
- Host: GitHub
- URL: https://github.com/leoture/MockSwift
- Owner: leoture
- License: mit
- Created: 2019-08-02T08:24:09.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2022-08-30T17:33:07.000Z (over 2 years ago)
- Last Synced: 2024-07-31T15:02:30.788Z (5 months ago)
- Topics: mock, playground, swift, swift-package-manager, test, xcode
- Language: Swift
- Homepage: https://adoring-varahamihira-bbe99d.netlify.app/documentation/
- Size: 1.85 MB
- Stars: 89
- Watchers: 8
- Forks: 7
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
- fucking-awesome-swift - MockSwift - Mock Framework that uses the power of property wrappers. (Libs / Testing)
- awesome-swift - MockSwift - Mock Framework that uses the power of property wrappers. (Libs / Testing)
- awesome-swift - MockSwift - MockSwift is a Mock library written in Swift. ` 📝 2 months ago` (Testing [🔝](#readme))
- awesome-swift - MockSwift - Mock Framework that uses the power of property wrappers. (Libs / Testing)
README
Welcome to MockSwift
=======[![Release](https://img.shields.io/github/v/release/leoture/MockSwift?color=red)](https://github.com/leoture/MockSwift/releases)
[![Build Status](https://github.com/leoture/MockSwift/workflows/Master/badge.svg?branch=master)](https://github.com/leoture/MockSwift/actions)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=leoture_MockSwift&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=leoture_MockSwift)
[![Netlify Status](https://api.netlify.com/api/v1/badges/08a89377-0a44-4f0e-a17c-9ee7d18e07bd/deploy-status)](https://app.netlify.com/sites/adoring-varahamihira-bbe99d/deploys)
[![Swift Package Manager compatible](https://img.shields.io/badge/Swift%20Package%20Manager-Compatible-brightgreen)](https://github.com/apple/swift-package-manager)
[![Swift](https://img.shields.io/badge/Swift-5.5-important)](https://swift.org)
[![license MIT](https://img.shields.io/badge/license-MIT-informational)](https://github.com/leoture/MockSwift/blob/master/LICENSE)**MockSwift** allows you to [**write mocks**](#write-mocks) and [**make better tests**](#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](https://site.mockito.org).###### Table of Contents
- [Installation](#installation)
- [Usage](#usage)
- [Documentation](#documentation)
- [Contribution](#contribution)
- [License](#license)# Installation
## Swift Package Manager
MockSwift has been designed to work with [Swift Package Manager](https://swift.org/package-manager/).
```swift
// swift-tools-version:5.3import 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
```swift
class AwesomeTests: XCTestCase {private var printer: Printer!
@Mock private var userService: UserServiceoverride 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.
```swift
struct User: Equatable {
let identifier: String
let name: String
}protocol UserService {
func fetch(identifier: String) -> User
}
```And you want to test this `UserCore` class.
```swift
class UserCore {
private let service: UserServiceinit(_ 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.
```swift
@Mock private var service: UserService// equivalent to
private var service: UserService = Mock()
```And easly configure it to fully test `UseCore`.
```swift
class UserCoreTests: XCTestCase {private var core: UserCore!
@Mock private var service: UserServiceoverride 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:
```swift
given(service).fetch(identifier: .any()).willReturn(expectedUser)// equivalent to
given(service) {
$0.fetch(identifier: .any()).willReturn(expectedUser)
}
``````swift
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.
```swift
@Mock({
$0.fetch(identifier: .any()).willReturn(expectedUser)
})
private var service: UserService
```### Then
`then()` enables you to verify calls.
example:```swift
then(service).fetch(identifier: .any()).called()// equivalent to
then(service) {
$0.fetch(identifier: .any()).called()
}
``````swift
then(service) {
$0.fetch(identifier: "current").called(times: >=2)$0.fetch(identifier: == "").called(times: 0)
}
```You can go further and verify order of calls
```swift
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**.```swift
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**.
```swift
@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.```swift
@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](https://github.com/leoture/MockSwift/blob/master/Templates/MockSwift.stencil) for [sourcery](https://github.com/krzysztofzablocki/Sourcery). You can use the `AutoMockable` annotation to generate code.
```swift
// 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**.
```swift
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**.
```swift
extension Given where WrappedType == UserService {
public func fetch(identifier: Predicate) -> Mockable {
mockable(identifier)
}
public func fetch(identifier: String) -> Mockable {
mockable(identifier)
}
}
```To allow call verification through `then()` method, you have to extend **Then**.
```swift
extension Then where WrappedType == UserService {
public func fetch(identifier: Predicate) -> Verifiable {
verifiable(identifier)
}
public func fetch(identifier: String) -> Verifiable {
verifiable(identifier)
}
}
```# Documentation
If you need more details about the API, you can check out our [API documentation](https://adoring-varahamihira-bbe99d.netlify.app).# Contribution
Would you like to contribute to MockSwift? Please read our [contributing guidelines](https://github.com/leoture/MockSwift/blob/master/CONTRIBUTING.md) and [code of conduct](https://github.com/leoture/MockSwift/blob/master/CODE_OF_CONDUCT.md).# License
MockSwift is released under the MIT license. [See LICENSE](https://github.com/leoture/MockSwift/blob/master/LICENSE) for details.# Credits
[![Thanks to JetBrains](https://raw.githubusercontent.com/leoture/MockSwift/master/jetbrains.svg?sanitize=true)](https://www.jetbrains.com/?from=MockSwift)