Product Promotion
0x5a.live
for different kinds of informations and explorations.
GitHub - leoture/MockSwift: MockSwift is a Mock library written in Swift.
MockSwift is a Mock library written in Swift. Contribute to leoture/MockSwift development by creating an account on GitHub.
Visit SiteGitHub - leoture/MockSwift: MockSwift is a Mock library written in Swift.
MockSwift is a Mock library written in Swift. Contribute to leoture/MockSwift development by creating an account on GitHub.
Powered by 0x5a.live 💗
Welcome to MockSwift
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
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.
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
Swift Resources
are all listed below.
Made with ❤️
to provide different kinds of informations and resources.