A Swifty mocking framework for Swift and Objective-C.
Mocking static members no longer requires referencing the staticMock
property when resetting mocks or clearing stubs/invocations.
// Old
reset(BirdMock.staticMock)
reset(type(of: mock(Bird.self)).staticMock)
// New
reset(BirdMock.self)
reset(type(of: mock(Bird.self))) // Preferred equivalent
You can now mock, stub, and verify async methods. Note that stubbing and verifying declarations requires the use of the await
keyword due to limitations with Swift’s overload resolution. Thanks to @ailtonvivaz for implementing this feature (#277).
protocol Bird {
func fetchMessage() async -> String
}
let bird = mock(Bird.self)
given(await bird.fetchMessage()).willReturn("Hello")
print(await bird.fetchMessage()) // Prints "Hello"
verify(await bird.fetchMessage()).wasCalled()
This release adds the ability to verify how mocks are initialized in cases where the metatype is provided to the system under test. Thanks to @myihsan for implementing this feature (#280).
protocol Bird {
init(name: String)
}
func createBird(type: Bird.Type) -> Bird {
return type.init(name: "Ryan")
}
let bird = createBird(type(of: mock(Bird.self)))
verify(bird.initialize(name: "Ryan")).wasCalled()
nil
check (#272)
Andrew Chang | Ian KeenSynchronized
wrapper (#275)
Andrew Chang
Mockingbird 0.19 improves support and guidance for setting up SwiftPM projects and packages. Previously, setting up a SwiftPM test target would use a path relative to $HOME
for the generator executable, which wasn’t portable between development environments. If you use SwiftPM, you should consider re-configuring test targets with the new configure
command to apply the fixes in 0.19.
The install
and download
commands have been replaced with configure
, which is a superset of the old commands but is not backwards compatible. Most workflows should be unaffected as these commands are only used to initially set up a project, not to generate mocks. See the Configure Command Options documentation for more information.
Mockingbird now provides a streamlined configurator to improve the setup process for all package managers, especially SwiftPM. It supports referencing executables located in the project’s default derived data directory and advanced features like generating mocks for source targets located in another project with the --srcproject
option. Supporting source files are also automatically downloaded and managed when running the configurator, making it even easier to set up projects for the first time.
$ mockingbird configure MockingbirdTests -- --targets MockingbirdTestsHost
🛠 Project: ~/mockingbird/Mockingbird.xcodeproj
🎯 Test Target: MockingbirdTests
🧰 Supporting sources: ~/mockingbird/MockingbirdSupport
✅ Downloaded supporting source files
✅ Added build phase 'Generate Mockingbird Mocks'
🎉 Successfully configured MockingbirdTests in 1s
🚀 Usage:
1. Initialize a mock in your test with `mock(SomeType.self)`
2. Build 'MockingbirdTests' (⇧⌘U) to generate mocks
3. Write some Swifty tests!
The README, wiki, and API reference are now unified and available at MockingbirdSwift.com which is powered by DocC, Apple’s fancy documentation compiler tool. The new site is better organized and prettier, but more importantly it’ll be much more searchable once Google finishes indexing it. The example projects have also been streamlined and include a new SwiftPM package example.
nil
values on Objective-C mocks implicitly bridging to NSNull
(#246)
Andrew Chang | molenick-mov | Bohdan OrlovAny?
(#248)
Andrew Chang | Bohdan OrlovThis release introduces the ability to mock Objective-C classes and protocols using the same syntax as Swift types. Objective-C mocking is type-safe and requires no codegen. You can find more information in the library evolution RFC.
let peripheral = mock(CBPeripheral.self)
given(peripheral.name).willReturn("Bird")
print(peripheral.name) // Prints "Bird"
verify(peripheral.name).wasCalled()
You can create partial mocks in 0.18 that forward calls to a specific object or its underlying superclass (for Swift class mocks).
protocol Bird {
var name: String { get }
}
class Crow: Bird {
let name: String
init(name: String) { self.name = name }
}
// Forward to an object
let bird = mock(Bird.self)
bird.forwardCalls(to: Crow(name: "Ryan"))
print(bird.name) // Prints "Ryan"
// Forward to the superclass
let crow = mock(Crow.self).initialize(name: "Ryan")
crow.forwardCallsToSuper()
print(crow.name) // Prints "Ryan"
It’s also possible to only forward specific invocations.
given(bird.name).willForward(to: Crow(name: "Ryan"))
given(crow.name).willForwardToSuper()
// Equivalent shorthand syntax
given(bird.name) ~> forward(to: Crow(name: "Ryan"))
given(crow.name) ~> forwardToSuper()
It’s now possible to stub and verify properties through their normal getter and setter syntax instead of relying on the synthesized accessors.
// Old
given(bird.getName()).willReturn("Ryan")
given(bird.setName(any())).will { name in /* ... */ }
// New
given(bird.name).willReturn("Ryan")
given(bird.name = any()).will { name in /* ... */ }
Previously the recommendation for keeping the framework and generator versions synchronized was to use CocoaPods, write some boilerplate, or check it into the repo. As of 0.17, Mockingbird now ships with a launcher which is guaranteed to run the same generator version as the framework and can pull signed (or unsigned) binaries from arbitrary artifact providers (defaults to the release artifacts on GitHub). To migrate existing integrations, follow the set-up steps again or manually modify the “Generate Mockingbird Mocks” build phase to call the ./mockingbird
launcher instead:
Pods/MockingbirdFramework/mockingbird generate ...
Carthage/Checkouts/mockingbird generate ...
DERIVED_DATA="$(echo "${OBJROOT}" | pcregrep -o1 '(/.*)/Build')"
REPO_PATH="${DERIVED_DATA}/SourcePackages/checkouts/mockingbird"
"${REPO_PATH}/mockingbird" generate ...
The default pruning method is now omit
instead of stub
unreferenced mock types, which should result in improved source stability and fewer generated mocks. A side effect is that in order to get code completion for previously unreferenced types the test bundle needs to be built once to generate the definitions. For the previous behavior, pass stub
to the generator --prune
option.
Level | Description |
---|---|
disable |
Always generate full thunks regardless of usage in tests. |
stub |
Generate partial definitions filled with fatalError . |
omit |
Don’t generate any definitions for unused types. |
The generator flag --disable-thunk-stubs
has been replaced with the option --prune [disable|stub|omit]
. Specify disable
for the thunk pruning method to reproduce the previous flag behavior.
Level | Description |
---|---|
disable |
Always generate full thunks regardless of usage in tests. |
stub |
Generate partial definitions filled with fatalError . |
omit |
Don’t generate any definitions for unused types. |
.xcodeproj
file (#171)
Andrew Chang
GH_ACCESS_TOKEN
to address rate limiting when downloading prebuilt binaries (#169)
Andrew Chang
This release unifies the mock initialization API for generic types.
class MyClass {}
protocol MyProtocol {}
class MyGenericClass<T> {}
protocol MyGenericProtocol {
associatedtype T
}
// Old
mock(MyClass.self)
mock(MyProtocol.self)
mock(MyGenericClassMock<Bool>.self)
mock(MyGenericProtocolMock<Bool>.self)
// New
mock(MyClass.self) // no change
mock(MyProtocol.self) // no change
mock(MyGenericClass<Bool>.self)
mock(MyGenericProtocol<Bool>.self)
Value provider has been simplified and no longer allows for hierarchical composition and decomposition.
// Old
var provider = ValueProvider()
provider.addSubprovider(.standardProvider)
provider.removeSubprovider(.standardProvider)
// New (mutating)
var provider = ValueProvider()
provider.add(.standardProvider)
// New (non-mutating)
let provider = ValueProvider() + .standardProvider
let provider = ValueProvider().adding(.standardProvider)