A convenient mocking framework for Swift

Overview

Mockingbird - Swift Mocking Framework

Package managers License Slack

// Mocking
let bird = mock(Bird.self)

// Stubbing
given(bird.getName()).willReturn("Ryan")

// Verification
verify(bird.fly()).wasCalled()

What is Mockingbird?

Mockingbird is a Swift mocking framework that lets you throw away your hand-written mocks and write clean, readable tests.

  • Expansive coverage of Swift language features
    • Mock classes and protocols in a single line of code
    • Support for generics, inheritance, static members, nested classes, type aliasing, etc.
  • Seamless integration with Xcode projects
    • Automatic discovery of source and dependency files
    • Handling of external types from third-party libraries
  • Convenient testing API
    • Clear stubbing and verification error messages
    • Support for asynchronous code, in order verification, default return value stubbing, etc.

Under the Hood

Mockingbird consists of two main components: the generator and the testing framework. Before each test bundle compilation, the generator mocks types by implementing protocols and subclassing classes. The testing framework then hooks into the generated code and provides APIs for mocking, stubbing, and verification.

A key design consideration was performance. Mockingbird runs an optimized parser built on SwiftSyntax and SourceKit that is ~30-40x faster than existing frameworks and supports a broad range of complex Swift features like generics and type qualification.

A Simple Example

Let’s say we wanted to test a Person class with a function that takes in a Bird.

protocol Bird {
  var canFly: Bool { get }
  func fly()
}

class Person {
  func release(_ bird: Bird) {
    guard bird.canFly else { return }
    bird.fly()
  }
}

With Mockingbird, it’s easy to stub return values and verify that mocked methods were called.

// Given a bird that can fly
let bird = mock(Bird.self)
given(bird.getCanFly()).willReturn(true)

// When a person releases the bird
Person().release(bird)

// Then the bird flies away
verify(bird.fly()).wasCalled()

Installation

Select your preferred dependency manager below for installation instructions and example projects.

CocoaPods

Add the framework to a test target in your Podfile, making sure to include the use_frameworks! option.

target 'MyAppTests' do
  use_frameworks!
  pod 'MockingbirdFramework', '~> 0.16'
end

Initialize the pod and install the CLI.

$ pod install
$ (cd Pods/MockingbirdFramework && make install-prebuilt)

Then download the starter supporting source files.

$ mockingbird download starter-pack

Finally, configure a test target to generate mocks for each listed source module. For advanced usages, see the available installer options and how to set up targets manually.

$ mockingbird install --target MyAppTests --sources MyApp MyLibrary1 MyLibrary2

Optional but recommended:

Have questions or issues?

Carthage

Add the framework to your Cartfile.

github "birdrides/mockingbird" ~> 0.16

Build the framework with Carthage, link it to your test target, and install the CLI.

$ carthage update
$ (cd Carthage/Checkouts/mockingbird && make install-prebuilt)

Then download the starter supporting source files.

$ mockingbird download starter-pack

Finally, configure a test target to generate mocks for each listed source module. For advanced usages, see the available installer options and how to set up targets manually.

$ mockingbird install --target MyAppTests --sources MyApp MyLibrary1 MyLibrary2

Optional but recommended:

Have questions or issues?

Swift Package Manager

Add the framework as a package dependency and link it to your test target.

  1. File > Swift Packages > Add Package Dependency…
  2. Enter https://github.com/birdrides/mockingbird for the repository URL and click Next
  3. Choose “Up to Next Minor” for the version and click Next
  4. Select your test target under “Add to Target” and click Finish
Click here if you are using a Package.swift manifest file instead.

Add Mockingbird to your package and test target dependencies.

let package = Package(
  name: "MyPackage",
  dependencies: [
    // Add the line below
    .package(name: "Mockingbird", url: "https://github.com/birdrides/mockingbird.git", .upToNextMinor(from: "0.16.0")),
  ],
  targets: [
    .testTarget(
      name: "MyPackageTests",
      dependencies: [
        "Mockingbird", // Add this line
      ]
    ),
  ]
)

In your project directory, initialize the package dependency and install the CLI.

$ xcodebuild -resolvePackageDependencies
$ DERIVED_DATA=$(xcodebuild -showBuildSettings | pcregrep -o1 'OBJROOT = (/.*)/Build')
$ (cd "${DERIVED_DATA}/SourcePackages/checkouts/mockingbird" && make install-prebuilt)

Then download the starter supporting source files.

$ mockingbird download starter-pack

Finally, configure a test target to generate mocks for each listed source module. For advanced usages, see the available installer options and how to set up targets manually.

$ mockingbird install --target MyPackageTests --sources MyPackage MyLibrary1 MyLibrary2

Optional but recommended:

Have questions or issues?

Usage

Mockingbird provides a comprehensive API reference generated with SwiftDoc.

  1. Mocking
  2. Stubbing
  3. Verification
  4. Argument Matching
  5. Miscellaneous

1. Mocking

Initialized mocks can be passed in place of the original type. Protocol mocks do not require explicit initialization while class mocks should be created using initialize(…).

protocol Bird {
  init(name: String)
}
class Tree {
  init(with bird: Bird) {}
}

let bird = mock(Bird.self)  // Protocol mock
let tree = mock(Tree.self).initialize(with: bird)  // Class mock

Generated mock types are suffixed with Mock and should not be coerced into their supertype.

let bird: BirdMock = mock(Bird.self)  // The concrete type is `BirdMock`
let inferredBird = mock(Bird.self)    // Type inference also works
let coerced: Bird = mock(Bird.self)   // Avoid upcasting mocks

Reset Mocks

Reset mocks and clear specific configurations during test runs.

reset(bird)                    // Reset everything
clearStubs(on: bird)           // Only remove stubs
clearDefaultValues(on: bird)   // Only remove default values
clearInvocations(on: bird)     // Only remove recorded invocations

2. Stubbing

Stubbing allows you to define custom behavior for mocks to perform.

given(bird.canChirp()).willReturn(true)
given(bird.canChirp()).willThrow(BirdError())
given(bird.canChirp(volume: any())).will { volume in
  return volume < 42
}

This is equivalent to the shorthand syntax using the stubbing operator ~>.

given(bird.canChirp()) ~> true
given(bird.canChirp()) ~> { throw BirdError() }
given(bird.canChirp(volume: any())) ~> { volume in
  return volume < 42
}

Stub Methods with Parameters

Match argument values to stub methods with parameters. Stubs added later have a higher precedence, so add stubs with specific matchers last.

given(bird.canChirp(volume: any())).willReturn(true)     // Any volume
given(bird.canChirp(volume: notNil())).willReturn(true)  // Any non-nil volume
given(bird.canChirp(volume: 10)).willReturn(true)        // Volume = 10

Stub Properties

Stub properties with their getter and setter methods.

given(bird.getName()).willReturn("Ryan")
given(bird.setName(any())).will { print($0) }

Getters can be stubbed to automatically save and return values.

given(bird.getName()).willReturn(lastSetValue(initial: ""))
print(bird.name)  // Prints ""
bird.name = "Ryan"
print(bird.name)  // Prints "Ryan"

Relaxed Stubs with Default Values

Mocks are strict by default, meaning that calls to unstubbed methods will trigger a test failure. Methods returning Void do not need to be stubbed in strict mode.

let bird = mock(Bird.self)
print(bird.name)  // Fails because `bird.getName()` is not stubbed
bird.fly()        // Okay because `fly()` has a `Void` return type

To return default values for unstubbed methods, use a ValueProvider with the initialized mock. Mockingbird provides preset value providers which are guaranteed to be backwards compatible, such as .standardProvider.

let bird = mock(Bird.self)
bird.useDefaultValues(from: .standardProvider)
print(bird.name)  // Prints ""

You can create custom value providers by registering values for types.

var valueProvider = ValueProvider()
valueProvider.register("Ryan", for: String.self)
bird.useDefaultValues(from: valueProvider)
print(bird.name)  // Prints "Ryan"

Values from concrete stubs always have a higher precedence than default values.

given(bird.getName()).willReturn("Ryan")
print(bird.name)  // Prints "Ryan"

bird.useDefaultValues(from: .standardProvider)
print(bird.name)  // Prints "Ryan"

Provide wildcard instances for generic types by conforming the base type to Providable and registering the type.

extension Array: Providable {
  public static func createInstance() -> Self? {
    return Array()
  }
}

// Provide an empty array for all specialized `Array` types
valueProvider.registerType(Array<Any>.self)

Stub a Sequence of Values

Methods that return a different value each time can be stubbed with a sequence of values. The last value will be used for all subsequent invocations.

given(bird.getName()).willReturn(sequence(of: "Ryan", "Sterling"))
print(bird.name)  // Prints "Ryan"
print(bird.name)  // Prints "Sterling"
print(bird.name)  // Prints "Sterling"

It’s also possible to stub a sequence of arbitrary behaviors.

given(bird.getName())
  .willReturn("Ryan")
  .willReturn("Sterling")
  .will { return Bool.random() ? "Ryan" : "Sterling" }

3. Verification

Verification lets you assert that a mock received a particular invocation during its lifetime.

verify(bird.fly()).wasCalled()

Verifying doesn’t remove recorded invocations, so it’s safe to call verify multiple times.

verify(bird.fly()).wasCalled()  // If this succeeds...
verify(bird.fly()).wasCalled()  // ...this also succeeds

Verify Methods with Parameters

Match argument values to verify methods with parameters.

verify(bird.canChirp(volume: any())).wasCalled()     // Called with any volume
verify(bird.canChirp(volume: notNil())).wasCalled()  // Called with any non-nil volume
verify(bird.canChirp(volume: 10)).wasCalled()        // Called with volume = 10

Verify Properties

Verify property invocations using their getter and setter methods.

verify(bird.getName()).wasCalled()
verify(bird.setName(any())).wasCalled()

Verify the Number of Invocations

It’s possible to verify that an invocation was called a specific number of times with a count matcher.

verify(bird.fly()).wasNeverCalled()            // n = 0
verify(bird.fly()).wasCalled(exactly(10))      // n = 10
verify(bird.fly()).wasCalled(atLeast(10))      // n ≥ 10
verify(bird.fly()).wasCalled(atMost(10))       // n ≤ 10
verify(bird.fly()).wasCalled(between(5...10))  // 5 ≤ n ≤ 10

Count matchers also support chaining and negation using logical operators.

verify(bird.fly()).wasCalled(not(exactly(10)))           // n ≠ 10
verify(bird.fly()).wasCalled(exactly(10).or(atMost(5)))  // n = 10 || n ≤ 5

Argument Capturing

An argument captor extracts received argument values which can be used in other parts of the test.

let bird = mock(Bird.self)
bird.name = "Ryan"

let nameCaptor = ArgumentCaptor<String>()
verify(bird.setName(nameCaptor.matcher)).wasCalled()

print(nameCaptor.value)  // Prints "Ryan"

In Order Verification

Enforce the relative order of invocations with an inOrder verification block.

// Verify that `fly` was called before `chirp`
inOrder {
  verify(bird.fly()).wasCalled()
  verify(bird.chirp()).wasCalled()
}

Pass options to inOrder verification blocks for stricter checks with additional invariants.

inOrder(with: .noInvocationsAfter) {
  verify(bird.fly()).wasCalled()
  verify(bird.chirp()).wasCalled()
}

Asynchronous Verification

Mocked methods that are invoked asynchronously can be verified using an eventually block which returns an XCTestExpectation.

DispatchQueue.main.async {
  Tree(with: bird).shake()
}

let expectation =
  eventually {
    verify(bird.fly()).wasCalled()
    verify(bird.chirp()).wasCalled()
  }

wait(for: [expectation], timeout: 1.0)

Verify Methods Overloaded by Return Type

Specify the expected return type to disambiguate overloaded methods.

protocol Bird {
  func getMessage<T>() -> T    // Overloaded generically
  func getMessage() -> String  // Overloaded explicitly
  func getMessage() -> Data
}

verify(bird.getMessage()).returning(String.self).wasCalled()

4. Argument Matching

Argument matching allows you to stub or verify specific invocations of parameterized methods.

Match Exact Values

Value types that explicitly conform to Equatable work out of the box. Note that structs able to synthesize Equatable conformance must still explicitly declare conformance.

struct Fruit: Equatable {
  let size: Int
}

verify(bird.eat(Fruit(size: 42))).wasCalled()
verify(bird.setName("Ryan")).wasCalled()

Class instances can be safely compared by reference.

class Tree {
  init(with bird: Bird) {
    bird.home = self
  }
}

let tree = Tree(with: bird)
verify(bird.setHome(tree)).wasCalled()

Match Wildcard Values and Non-Equatable Types

Argument matchers allow for wildcard and custom matching of arguments that don’t conform to Equatable.

any()                    // Matches any value
any(of: 1, 2, 3)         // Matches any value in {1, 2, 3}
any(where: { $0 > 42 })  // Matches any number greater than 42
notNil()                 // Matches any non-nil value

For methods overloaded by parameter type (such as with generics), using a matcher may cause ambiguity for the compiler. You can help the compiler by specifying an explicit type in the matcher.

any(Int.self)
any(Int.self, of: 1, 2, 3)
any(Int.self, where: { $0 > 42 })
notNil(String?.self)

You can also match elements or keys within collection types.

any(containing: 1, 2, 3)  // Matches any collection with values {1, 2, 3}
any(keys: "a", "b", "c")  // Matches any dictionary with keys {"a", "b", "c"}
any(count: atMost(42))    // Matches any collection with at most 42 elements
notEmpty()                // Matches any non-empty collection

Match Floating Point Values

Mathematical operations on floating point numbers can cause loss of precision. Fuzzily match floating point arguments instead of using exact values to increase the robustness of tests.

around(10.0, tolerance: 0.01)

5. Miscellaneous

Excluding Files

You can exclude unwanted or problematic sources from being mocked by adding a .mockingbird-ignore file. Mockingbird follows the same pattern format as .gitignore and scopes ignore files to their enclosing directory.

Using Supporting Source Files

Supporting source files are used by the generator to resolve inherited types defined outside of your project. Although Mockingbird provides a preset “starter pack” for basic compatibility with common system frameworks, you will occasionally need to add your own definitions for third-party library types. Please see Supporting Source Files for more information.

Thunk Pruning

To improve compilation times for large projects, Mockingbird only generates mocking code (known as thunks) for types used in tests. Unused types can either produce “thunk stubs” or no code at all depending on the pruning level specified.

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.

Usage is determined by statically analyzing test target sources for calls to mock(SomeType.self), which may not work out of the box for projects that indirectly synthesize types such as through Objective-C based dependency injection.

  • Option 1: Explicitly reference each indirectly synthesized type in your tests, e.g. _ = mock(SomeType.self). References can be placed anywhere in the test target sources, such as in the setUp method of a test case or in a single file.
  • Option 2: Disable pruning entirely by setting the prune level with --prunelevel disable. Note that this may increase compilation times for large projects.

Mockingbird CLI

Generate

Generate mocks for a set of targets in a project.

mockingbird generate

Option Default Value Description
--targets (required) List of target names to generate mocks for.
--project (inferred) Path to an .xcodeproj file or a JSON project description.
--srcroot (inferred) The directory containing your project’s source files.
--outputs (inferred) List of mock output file paths for each target.
--support (inferred) The directory containing supporting source files.
--testbundle (inferred) The name of the test bundle using the mocks.
--header (none) Content to add at the beginning of each generated mock file.
--condition (none) Compilation condition to wrap all generated mocks in, e.g. DEBUG.
--diagnostics (none) List of diagnostic generator warnings to enable.
--prune stub The pruning method to use on unreferenced types.
Flag Description
--only-protocols Only generate mocks for protocols.
--disable-module-import Omit @testable import <module> from generated mocks.
--disable-swiftlint Disable all SwiftLint rules in generated mocks.
--disable-cache Ignore cached mock information stored on disk.
--disable-relaxed-linking Only search explicitly imported modules.

Install

Configure a test target to use mocks.

mockingbird install

Option Default Value Description
--target (required) The name of a test target to configure.
--sources (required) List of target names to generate mocks for.
--project (inferred) Path to an .xcodeproj file or a JSON project description.
--srcroot (inferred) The directory containing your project’s source files.
--outputs (inferred) List of mock output file paths for each target.
--support (inferred) The directory containing supporting source files.
--header (none) Content to add at the beginning of each generated mock file.
--condition (none) Compilation condition to wrap all generated mocks in, e.g. DEBUG.
--diagnostics (none) List of diagnostic generator warnings to enable.
--loglevel (none) The log level to use when generating mocks, quiet or verbose.
--prune stub The pruning method to use on unreferenced types.
Flag Description
--preserve-existing Don’t overwrite previously installed configurations.
--asynchronous Generate mocks asynchronously in the background when building.
--only-protocols Only generate mocks for protocols.
--disable-swiftlint Disable all SwiftLint rules in generated mocks.
--disable-cache Ignore cached mock information stored on disk.
--disable-relaxed-linking Only search explicitly imported modules.

Uninstall

Remove Mockingbird from a test target.

mockingbird uninstall

Option Default Value Description
--targets (required) List of target names to uninstall the Run Script Phase.
--project (inferred) Your project’s .xcodeproj file.
--srcroot (inferred) The directory containing your project’s source files.

Download

Download and unpack a compatible asset bundle. Bundles will never overwrite existing files on disk.

mockingbird download <asset>

Asset Description
starter-pack Starter supporting source files.

Global Options

Flag Description
--verbose Log all errors, warnings, and debug messages.
--quiet Only log error messages.

Inferred Paths

--project

Mockingbird first checks the environment variable PROJECT_FILE_PATH set by the Xcode build context and then performs a shallow search of the current working directory for an .xcodeproj file. If multiple .xcodeproj files exist then you must explicitly provide a project file path.

--srcroot

Mockingbird checks the environment variables SRCROOT and SOURCE_ROOT set by the Xcode build context and then falls back to the directory containing the .xcodeproj project file. Note that source root is ignored when using JSON project descriptions.

--outputs

By Mockingbird generates mocks into the directory $(SRCROOT)/MockingbirdMocks with the file name $(PRODUCT_MODULE_NAME)Mocks.generated.swift.

--support

Mockingbird recursively looks for supporting source files in the directory $(SRCROOT)/MockingbirdSupport.

--testbundle

Mockingbird checks the environment variables TARGET_NAME and TARGETNAME set by the Xcode build context and verifies that it refers to a valid Swift unit test target. The test bundle option must be set when using JSON project descriptions in order to enable thunk stubs.

Additional Resources

Examples and Tutorials

Help and Documentation

Comments
  • MyTypeMock does not conform to protocol NSObjectProtocol

    MyTypeMock does not conform to protocol NSObjectProtocol

    Hi,

    In my project, there are supporting source files related to NSObjectProtocol. but the error "MyTypeDelegateMock does not conform to protocol NSObjectProtocol" is not resolved.

    protocol DTPhotoViewerControllerDelegate: NSObjectProtocol { } protocol MyTypeDelegate: DTPhotoViewerControllerDelegate { }

    In MyProjectMocks.generated.swift file, i have this error:

    // MARK: - Mocked MyTypeDelegate

    public final class MyTypeDelegateMock: MyProject.MyTypeDelegate, Mockingbird.Mock { }

    more info needed 
    opened by fereshteh-zargaran 10
  • Unable get generate file

    Unable get generate file

    can you guide me install and generating mock file. I have it tried by below way. My Used file as below. Protocol -> LoginProtocol Manager -> LoginApiManager TestFile -> LoginTests project target -> Login test target -> LoginTest

    // Below command generate blur file of generated mocs but cant accessible in project

    mockingbird install
    --project Login.xcodeproj
    --target LoginExample
    --destination LoginTests

    Can you guide me how to generate LoginProtocol mocs .

    opened by DhirajChaudhari 10
  • Feature request: Custom URL to download starter pack

    Feature request: Custom URL to download starter pack

    New Issue Checklist

    • [x] I updated my Mockingbird framework and CLI to the latest version
    • [x] I searched for existing GitHub issues

    Description

    During installation, mockingbird download starter-pack should provide the possibility to enter a custom URL. Hardcoding the url to github is not nice ;)

    private func assetBundleUrl(for fileName: String) -> Foundation.URL {
        return Foundation.URL(string:
          "https://github.com/birdrides/mockingbird/releases/download/\(mockingbirdVersion)/\(fileName)"
        )!
      }
    

    Environment

    • Mockingbird CLI version (0.16.0)
    • Xcode 12.5.1 and macOS 11.4
    • Swift version (5.4.2)
    • Installation method (SPM)
    • Unit testing framework (XCTest)
    • Does your project use .mockingbird-ignore? No
    • Are you using supporting source files? No
    enhancement 
    opened by ynx-zeissl 8
  • Module 'Mockingbird' was not compiled for testing

    Module 'Mockingbird' was not compiled for testing

    New Issue Checklist

    • [x] I updated my Mockingbird framework and CLI to the latest version
    • [x] I searched for existing GitHub issues

    Description

    Framework Bug

    Module 'Mockingbird' was not compiled for testing

    Installation method -> Swift Package Manager Xcode version -> 12.4 macOS version -> 10.15.7 mockingbird version -> 16.0 swift --version -> Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28) Test Suite -> XCTest

    Issue

    After following installation instructions and compiling our project everything generates and builds, but when attempting to run the test suite it fails to compile with error Module 'Mockingbird' was not compiled for testing in the *.generated.swift file. Framework was added under our 'Tests' target

    Screenshot 2021-01-11 at 11 07 18

    documentation 
    opened by EvanMasterson 8
  • Use without xcode - on purely swift package based projects

    Use without xcode - on purely swift package based projects

    New Issue Checklist

    • [x] I updated my Mockingbird framework and CLI to the latest version
    • [x] I searched for existing GitHub issues

    Description

    The code I talk about is in a draft PR #165 As mocking could be very helpful for projects that do not require you to have an Xcode project I would like to alter the project so I can use it on my server side projects. I'm facing some issues with the way the project is setup.

    • loading the dlib is not working as it is missing the swiftSyntaxParserDylib variable in main
    • just opening the open Package.swift will make xcode resolve the dependencies. This works but then I cannot build because of my first bullet
    • The instructions say you can add Mockingbird to an existing project Package.swift file. But this results in an error if I follow the instructions. dependency 'Mockingbird' in target 'UseCaseInjectTests' requires explicit declaration; provide the name of the package dependency with

    To solve this I followed the following steps, unsuccessful so far

    1. I followed the contribution guidelines and ran the make setup-project
    2. Then I cd sources to inspect the package
    3. I tried to add product Mockingbird as a dependency to the commented out test target
    4. added the needed files for a test target
    5. declared swiftSyntaxParserDylib manually as
    let file = #file
    let dataDlib = file.replacingOccurrences(of: "", with: "") // this is a workaround to be able to build it, not pointing to correct file as this depends on how you build it
    let swiftSyntaxParserDylib = Resource(
        encodedData: try Data(contentsOf: URL(fileURLWithPath: dataDlib)).base64EncodedString(),
        fileName: "lib_InternalSwiftSyntaxParser.dylib"
    )
    

    This fixed the build and I could import Mockingbird in my added test target. 6. Then I followed the instructions to Manual-Setup

    But I lack a bit of background to be able to get this working. What I like to do on Package.swift only projects is:

    • generate the mocks from targets defined in the Package.swift (by default just all except test targets)
    • add some code to a git hook pre-push so it generates the mocks and runs tests before I can push

    As this is how I would like to use it without the hassle of having to generate an XCode project I filed this issue. Could you help me get started?

    Framework Bugs

    Unable to include the Mockingbird framework in a purely swift package project without Xcode.

    As this outputs error

    dependency 'Mockingbird' in target '<#MyTestTarget#>' requires explicit declaration; provide the name of the package dependency with
    

    Also adding it with .product(name: "Mockingbird", package: "mockingbird") did not do the trick.

    Environment

    • Mockingbird CLI version (0.14.0)
    • Xcode and macOS version (11.6)
    • Swift version (5.2)
    • Installation method (SPM)
    • Unit testing framework (XCTest)
    • Are you using supporting source files? Not sure how to, maybe this is the problem that I'm missing something?
    enhancement 
    opened by doozMen 8
  • Swift concurrency async/await support

    Swift concurrency async/await support

    New Issue Checklist

    • [x] I updated my Mockingbird framework and CLI to the latest version
    • [x] I searched for existing GitHub issues

    Description

    With Swift 5.5 and iOS 15, we can use the new swift concurrency (async/await) which seems not yet handled by the generator. We can write functions like:

    • func sendConcurrently() async -> String
    • func sendConcurrently() async throws -> String

    It would be great to handle this new syntax.

    Generator Bugs

    1. A minimal example of the original source For example, starting a new project and adding this protocol & class

    public protocol MyAppProtocol {
        @available(iOS 15.0.0, *)
        func sendConcurrently() async -> String
        func send() -> String
    }
    
    
    open class MyAppImplementation: MyAppProtocol {
    
       @available(iOS 15.0.0, *)
        public func sendConcurrently() async -> String {
            "Hello Concurrent World!"
        }
        
        public func send() -> String {
            "Hello World!"
        }
    }
    

    2. The actual mocking code generated will generate this

    // MARK: - Mocked MyAppImplementation
    ...
      // MARK: Mocked `sendConcurrently`()
      public override func `sendConcurrently`() -> String {  // /!\ error: Method does not override any method from its superclass
        return self.mockingbirdContext.mocking.didInvoke(Mockingbird.SwiftInvocation(selectorName: "`sendConcurrently`() -> String", selectorType: Mockingbird.SelectorType.method, arguments: [], returnType: Swift.ObjectIdentifier((String).self))) {
          self.mockingbirdContext.recordInvocation($0)
          let mkbImpl = self.mockingbirdContext.stubbing.implementation(for: $0)
          if let mkbImpl = mkbImpl as? () -> String { return mkbImpl() }
          for mkbTargetBox in self.mockingbirdContext.proxy.targets(for: $0) {
            switch mkbTargetBox.target {
            case .super:
              return super.`sendConcurrently`() // /!\ error: 'async' call in a function that does not support concurrency
            case .object(let mkbObject):
              guard var mkbObject = mkbObject as? MockingbirdSupertype else { break }
              let mkbValue: String = mkbObject.`sendConcurrently`() // /!\ error: 'async' call in a function that does not support concurrency
              self.mockingbirdContext.proxy.updateTarget(&mkbObject, in: mkbTargetBox)
              return mkbValue
            }
          }
          if let mkbValue = self.mockingbirdContext.stubbing.defaultValueProvider.value.provideValue(for: (String).self) { return mkbValue }
          self.mockingbirdContext.stubbing.failTest(for: $0, at: self.mockingbirdContext.sourceLocation)
        }
      }
    
      public func `sendConcurrently`() -> Mockingbird.Mockable<Mockingbird.FunctionDeclaration, () -> String, String> {
        return Mockingbird.Mockable<Mockingbird.FunctionDeclaration, () -> String, String>(mock: self, invocation: Mockingbird.SwiftInvocation(selectorName: "`sendConcurrently`() -> String", selectorType: Mockingbird.SelectorType.method, arguments: [], returnType: Swift.ObjectIdentifier((String).self)))
      }
    
    // MARK: - Mocked MyAppProtocol
    ...
      // MARK: Mocked `sendConcurrently`()
      @available(iOS 15.0.0, *)
      public func `sendConcurrently`() -> String {
        return self.mockingbirdContext.mocking.didInvoke(Mockingbird.SwiftInvocation(selectorName: "`sendConcurrently`() -> String", selectorType: Mockingbird.SelectorType.method, arguments: [], returnType: Swift.ObjectIdentifier((String).self))) {
          self.mockingbirdContext.recordInvocation($0)
          let mkbImpl = self.mockingbirdContext.stubbing.implementation(for: $0)
          if let mkbImpl = mkbImpl as? () -> String { return mkbImpl() }
          for mkbTargetBox in self.mockingbirdContext.proxy.targets(for: $0) {
            switch mkbTargetBox.target {
            case .super:
              break
            case .object(let mkbObject):
              guard var mkbObject = mkbObject as? MockingbirdSupertype else { break }
              let mkbValue: String = mkbObject.`sendConcurrently`() // /!\ error: 'async' call in a function that does not support concurrency
              self.mockingbirdContext.proxy.updateTarget(&mkbObject, in: mkbTargetBox)
              return mkbValue
            }
          }
          if let mkbValue = self.mockingbirdContext.stubbing.defaultValueProvider.value.provideValue(for: (String).self) { return mkbValue }
          self.mockingbirdContext.stubbing.failTest(for: $0, at: self.mockingbirdContext.sourceLocation)
        }
      }
    
      @available(iOS 15.0.0, *)
      public func `sendConcurrently`() -> Mockingbird.Mockable<Mockingbird.FunctionDeclaration, () -> String, String> {
        return Mockingbird.Mockable<Mockingbird.FunctionDeclaration, () -> String, String>(mock: self, invocation: Mockingbird.SwiftInvocation(selectorName: "`sendConcurrently`() -> String", selectorType: Mockingbird.SelectorType.method, arguments: [], returnType: Swift.ObjectIdentifier((String).self)))
      }
    
    • error: Method does not override any method from its superclass
    • error: 'async' call in a function that does not support

    3. The expected mocking code that should be generated (or a description) I'm not sure of what should be generated (which depends of how it will be implemented) but what I can say is that:

    • the generated signature functions should be
    @available(iOS 15.0.0, *) public func `sendConcurrently`() async -> String
    

    which throw away the "Method does not override any method from its superclass" error.

    • not sure about the implementation but may be something like (seems to work on 0.18+):
    // MockingContext.swift
    @available(iOS 15.0.0, *)
        func didInvoke<T, I: Invocation>(_ invocation: I, evaluating thunk: (I) async -> T) async -> T {
          // Ensures that the thunk is evaluated prior to recording the invocation.
          defer { didInvoke(invocation) }
          return await thunk(invocation)
        }
    
    // MARK: - Mocked MyAppImplementation
    ...
    // MARK: Mocked `sendConcurrently`()
        @available(iOS 15.0.0, *)
        public override func `sendConcurrently`() async -> String {
            await self.mockingbirdContext.mocking.didInvoke(Mockingbird.SwiftInvocation(selectorName: "`sendConcurrently`() -> String", selectorType: Mockingbird.SelectorType.method, arguments: [], returnType: Swift.ObjectIdentifier((String).self))) { invocation async in
                self.mockingbirdContext.recordInvocation(invocation)
                let mkbImpl = self.mockingbirdContext.stubbing.implementation(for: invocation)
                if let mkbImpl = mkbImpl as? () -> String { return mkbImpl() }
                for mkbTargetBox in self.mockingbirdContext.proxy.targets(for: invocation) {
                    switch mkbTargetBox.target {
                    case .super:
                        return await super.`sendConcurrently`()
                    case .object(let mkbObject):
                        guard var mkbObject = mkbObject as? MockingbirdSupertype else { break }
                        let mkbValue: String = await mkbObject.`sendConcurrently`()
                        self.mockingbirdContext.proxy.updateTarget(&mkbObject, in: mkbTargetBox)
                        return mkbValue
                    }
                }
                if let mkbValue = self.mockingbirdContext.stubbing.defaultValueProvider.value.provideValue(for: (String).self) { return mkbValue }
                self.mockingbirdContext.stubbing.failTest(for: invocation, at: self.mockingbirdContext.sourceLocation)
            }
        }
        
        public func `sendConcurrently`() -> Mockingbird.Mockable<Mockingbird.FunctionDeclaration, () -> String, String> {
            return Mockingbird.Mockable<Mockingbird.FunctionDeclaration, () -> String, String>(mock: self, invocation: Mockingbird.SwiftInvocation(selectorName: "`sendConcurrently`() -> String", selectorType: Mockingbird.SelectorType.method, arguments: [], returnType: Swift.ObjectIdentifier((String).self)))
        }
    
    
    // MARK: - Mocked MyAppProtocol
    ...
    // MARK: Mocked `sendConcurrently`()
        @available(iOS 15.0.0, *)
        public func `sendConcurrently`() async -> String {
            return await self.mockingbirdContext.mocking.didInvoke(Mockingbird.SwiftInvocation(selectorName: "`sendConcurrently`() -> String", selectorType: Mockingbird.SelectorType.method, arguments: [], returnType: Swift.ObjectIdentifier((String).self))) { invocation async in
                self.mockingbirdContext.recordInvocation(invocation)
                let mkbImpl = self.mockingbirdContext.stubbing.implementation(for: invocation)
                if let mkbImpl = mkbImpl as? () -> String { return mkbImpl() }
                for mkbTargetBox in self.mockingbirdContext.proxy.targets(for: invocation) {
                    switch mkbTargetBox.target {
                    case .super:
                        break
                    case .object(let mkbObject):
                        guard var mkbObject = mkbObject as? MockingbirdSupertype else { break }
                        let mkbValue: String = await mkbObject.`sendConcurrently`()
                        self.mockingbirdContext.proxy.updateTarget(&mkbObject, in: mkbTargetBox)
                        return mkbValue
                    }
                }
                if let mkbValue = self.mockingbirdContext.stubbing.defaultValueProvider.value.provideValue(for: (String).self) { return mkbValue }
                self.mockingbirdContext.stubbing.failTest(for: invocation, at: self.mockingbirdContext.sourceLocation)
            }
        }
    
      public func `sendConcurrently`() -> Mockingbird.Mockable<Mockingbird.FunctionDeclaration, () -> String, String> {
        return Mockingbird.Mockable<Mockingbird.FunctionDeclaration, () -> String, String>(mock: self, invocation: Mockingbird.SwiftInvocation(selectorName: "`sendConcurrently`() -> String", selectorType: Mockingbird.SelectorType.method, arguments: [], returnType: Swift.ObjectIdentifier((String).self)))
      }
    

    Tips for others/waiting support On our side (at work), we're staying on 0.17. For the several files we need to handle, we copy/paste wrong generated mocks to a manual-mock file that we maintain and only change the signature to @available(iOS 15.0.0, *) public func `sendConcurrently`() async -> String which seems enough. (On 0.18+ it requires more works). Then we exclude those files with .mockingbird-ignore from being generated to avoid conflict.

    Work's project compile and tests runs without edge cases for now.

    func testExample() async {
        let myProtocol = mock(MyAppProtocol.self)
        given(myProtocol.sendConcurrently()).willReturn("Hello Concurrent World!")
        let result: String = await myProtocol.sendConcurrently()
        XCTAssertEqual(result, "Hello Concurrent World!")
    }
    

    Environment

    • Mockingbird CLI version: mockingbird version: 0.18.1
    • Xcode and macOS version (are you running a beta?): XCode beta 13.0 beta 5 (13A5212g) & macOS BigSur 11.3 (20E232)
    • Swift version: swift version: 5.5
    • Installation method: CocoaPods
    • Unit testing framework: XCTest
    • Does your project use .mockingbird-ignore?: Yes
    • Are you using supporting source files?: Yes
    generator bug reproducible swift 5.5 
    opened by paul1893 7
  • Receiving

    Receiving "Cannot infer the argument position of 'any()' " when used with optional named parameters

    New Issue Checklist

    • [X ] I updated my Mockingbird framework and CLI to the latest version
    • [ X] I searched for existing GitHub issues

    Description

    I recently upgraded my Mockingbird installation, and suddenly started receiving slews of the following error across my entire test suite when running my tests:

    Cannot infer the argument position of 'any()' when used in this context
    
    Wrap usages of 'any()' in an explicit argument position, for example:
       firstArg(any())
       secondArg(any())
       arg(any(), at: 3) (co.bird.mockingbird.TestFailure)
    

    Almost every instance where this is occurring is a case in which the method has default parameters. For example, if the protocol is:

    protocol MyServicable {
      func makeAPICall(endpoint: string, callback: (() -> Void)?)
    }
    

    and it has the extension:

    extension MyServicable {
      func makeAPICall(endpoint: string, callback: (() -> Void)? = nil) {
        return self.makeAPICall(endpoint, callback);
      }
    }
    

    and it has being mocked as:

    let service = mock(MyServicable.self)
    
    service.makeAPICall("https://my.com/endpoint", callback: any())
    

    then this error is thrown. This wasn't happening with previous versions of Mockingbird, so I'm wondering what might have changed to cause this issue.

    Framework Bugs

    You should be able to write a reproduction case following the example above – if needed I can set up a separate repo to demonstrate.

    Environment

    • Mockingbird CLI version (mockingbird version) 0.18.1
    • Xcode and macOS version (are you running a beta?) XCode 12.5.1, macOS 11.5.2
    • Swift version (swift --version) 5.4.2
    • Installation method (CocoaPods, Carthage, from source, etc) CocoaPods
    • Unit testing framework (XCTest, Quick + Nimble, etc) Quick + Nimble
    • Does your project use .mockingbird-ignore? No
    • Are you using supporting source files? Yes
    more info needed framework bug 
    opened by Nickersoft 6
  • Unable to verify initializer since 0.18.0

    Unable to verify initializer since 0.18.0

    New Issue Checklist

    • [x] I updated my Mockingbird framework and CLI to the latest version
    • [x] I searched for existing GitHub issues

    Description

    I depend on the implementation below in a special case.

    https://github.com/birdrides/mockingbird/blob/13ee8ab4346bf65c51612305a897dffcfab45e5c/Sources/MockingbirdGenerator/Generator/Templates/InitializerMethodTemplate.swift#L76-L82

    But it has been deleted by #217.

    Do we have to delete it for supporting partial mocks, or it's deleted unintentionally?

    enhancement 
    opened by myihsan 5
  • NSInvalidArgumentException

    NSInvalidArgumentException

    New Issue Checklist

    • [x] I updated my Mockingbird framework and CLI to the latest version
    • [x] I searched for existing GitHub issues

    Description

    The test is failing due to: *** -[NSProxy methodSignatureForSelector:] called! (NSInvalidArgumentException)

    Im having:

    class Service {
      func test(vc: UIViewController) {}
    }
    

    And want to stub the service like this: given(service.test(vc: any()))

    The result is: TreeTests.testDroppingLargeFruit_doesNothing(): *** -[NSProxy methodSignatureForSelector:] called! (NSInvalidArgumentException)

    Environment

    • Mockingbird CLI version (0.18.1)
    • Xcode and macOS version: Xcode 12.5.1 and 13,OSX 11.4
    • Swift version: Apple Swift version 5.4.2 (swiftlang-1205.0.28.2 clang-1205.0.19.57)
    • Installation method: CocoaPods
    • Unit testing framework: XCTest
    • Does your project use .mockingbird-ignore? No
    • Are you using supporting source files? No
    reproducible framework bug obj-c 
    opened by jdschin 5
  • Failure to decode project description generated by `swiftpm`.

    Failure to decode project description generated by `swiftpm`.

    New Issue Checklist

    • [x] I updated my Mockingbird framework and CLI to the latest version
    • [x] I searched for existing GitHub issues

    Description

    Mockingbird cannot parse the json description of my Swift package.

    error: keyNotFound(CodingKeys(stringValue: "dependencies", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "targets", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"dependencies\", intValue: nil) (\"dependencies\").", underlyingError: nil))
    

    redacted-desc.json.zip (I redacted some local paths).

    mockingbird generate --project redacted-desc.json --target CompanyTextInput --support MockingbirdSupport 
    

    Environment

    0.16.0 / Big Sur / Installed with Swift Package Manager / XCTest / Uses .mockingbird-ignore / Uses supporting files

    Apple Swift version 5.4.2 (swiftlang-1205.0.28.2 clang-1205.0.19.57) Target: x86_64-apple-darwin20.5.0

    • Mockingbird CLI version (mockingbird version)
    • Xcode and macOS version (are you running a beta?)
    • Swift version (swift --version)
    • Installation method (CocoaPods, Carthage, from source, etc)
    • Unit testing framework (XCTest, Quick + Nimble, etc)
    • Does your project use .mockingbird-ignore?
    • Are you using supporting source files?
    good first issue reproducible installer bug 
    opened by kielgillard 5
  • Installation with CocoaPods

    Installation with CocoaPods

    Can't install the framework with CocoaPods. During the installation process "pod install" error below is received.

    [!] CDN: trunk Repo update failed - 7 error(s): CDN: trunk URL couldn't be downloaded: https://raw.githubusercontent.com/CocoaPods/Specs/master/Specs/4/a/1/MockingbirdFramework/0.10.0/MockingbirdFramework.podspec.json Response: SSL peer certificate or SSH remote key was not OK CDN: trunk URL couldn't be downloaded: https://raw.githubusercontent.com/CocoaPods/Specs/master/Specs/4/a/1/MockingbirdFramework/0.11.0/MockingbirdFramework.podspec.json Response: SSL peer certificate or SSH remote key was not OK CDN: trunk URL couldn't be downloaded: https://raw.githubusercontent.com/CocoaPods/Specs/master/Specs/4/a/1/MockingbirdFramework/0.6.0/MockingbirdFramework.podspec.json Response: SSL peer certificate or SSH remote key was not OK CDN: trunk URL couldn't be downloaded: https://raw.githubusercontent.com/CocoaPods/Specs/master/Specs/4/a/1/MockingbirdFramework/0.6.1/MockingbirdFramework.podspec.json Response: SSL peer certificate or SSH remote key was not OK CDN: trunk URL couldn't be downloaded: https://raw.githubusercontent.com/CocoaPods/Specs/master/Specs/4/a/1/MockingbirdFramework/0.7.0/MockingbirdFramework.podspec.json Response: SSL peer certificate or SSH remote key was not OK CDN: trunk URL couldn't be downloaded: https://raw.githubusercontent.com/CocoaPods/Specs/master/Specs/4/a/1/MockingbirdFramework/0.8.0/MockingbirdFramework.podspec.json Response: SSL peer certificate or SSH remote key was not OK CDN: trunk URL couldn't be downloaded: https://raw.githubusercontent.com/CocoaPods/Specs/master/Specs/4/a/1/MockingbirdFramework/0.9.0/MockingbirdFramework.podspec.json Response: SSL peer certificate or SSH remote key was not OK

    more info needed 
    opened by llOldmenll 5
  • Unable to stub closure in static function

    Unable to stub closure in static function

    New Issue Checklist

    Overview

    When I try to stub closure with will in a static function, it shows error "Unable to infer type of a closure parameter", if I specify the type in the closure parameter, it can be built successfully, but crash when running test.

    Example

    Source class

    class NetworkHelper {
        // MARK: - Network requests
        static func get(
            url: URL,
            token: String?,
            completion: @escaping (Data?, URLResponse?, Error?) -> Void
        ) {
            var request = URLRequest(url: url)
            request.httpMethod = "GET"
            // Sample server doesn't need a token as it runs locally
            if let token {
                request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
            }
    
            URLSession.shared.dataTask(with: request, completionHandler: completion).resume()
        }
    }
    
    

    Test class

    func testRequestOtpSuccess() throws {
            let helper = type(of: mock(NetworkHelper.self))
            given(helper.get(url: any(), token: any(), completion: any())).will { completion in //This will show error when building
                completion(nil, nil, nil)
            }
            // The following ways will crash the app
            // error: memory read failed for 0x0
            given(helper.get(url: any(), token: any(), completion: any())).will { (completion: (Data?, URLResponse?, Error?) -> Void) in
                completion(nil, nil, nil)
            }
            given(helper.get(url: any(), token: any(), completion: any())).will {
            }
        }
    

    Expected Behavior

    It should be able to stub and run without crashing

    Environment

    • Mockingbird CLI version (0.20.0)
    • Xcode and Swift version (swift-driver version: 1.62.15 Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51) Target: arm64-apple-macosx13.0)
    • Package manager (SPM project)
    • Unit testing framework (XCTest)
    • Custom configuration
      • [ ] Mockingbird ignore files
      • [ ] Supporting source files
    framework bug 
    opened by terenceLuffy 0
  • Generator fails to create mock for the simplest PAT

    Generator fails to create mock for the simplest PAT

    Overview

    Mockingbird site advertises the library as if it supports the Protocols with generic type here https://mockingbirdswift.com/feature-comparison but in reality, it fails for simplest generic protocol.

    Example

    protocol Mapper{
        associatedtype I
        associatedtype O
        
        func map(i: I) -> O
    }
    

    Generated code

    private let mkbGenericStaticMockContext = Mockingbird.GenericStaticMockContext()
    
    // MARK: - Mocked Mapper
    public final class MapperMock<I, O>: Mappa.Mapper, Mockingbird.Mock {
      typealias MockingbirdSupertype = Mappa.Mapper
      public static var mockingbirdContext: Mockingbird.Context { return mkbGenericStaticMockContext.resolve(["MapperMock<I, O>", Swift.ObjectIdentifier(I.self).debugDescription, Swift.ObjectIdentifier(O.self).debugDescription]) }
      public let mockingbirdContext = Mockingbird.Context(["generator_version": "0.20.0", "module_name": "Mappa"])
    
      fileprivate init(sourceLocation: Mockingbird.SourceLocation) {
        self.mockingbirdContext.sourceLocation = sourceLocation
        MapperMock.mockingbirdContext.sourceLocation = sourceLocation
      }
    
      // MARK: Mocked `map`(`i`: I)
      public func `map`(`i`: I) -> O {
        return self.mockingbirdContext.mocking.didInvoke(Mockingbird.SwiftInvocation(selectorName: "`map`(`i`: I) -> O", selectorType: Mockingbird.SelectorType.method, arguments: [Mockingbird.ArgumentMatcher(`i`)], returnType: Swift.ObjectIdentifier((O).self))) {
          self.mockingbirdContext.recordInvocation($0)
          let mkbImpl = self.mockingbirdContext.stubbing.implementation(for: $0)
          if let mkbImpl = mkbImpl as? (I) -> O { return mkbImpl(`i`) }
          if let mkbImpl = mkbImpl as? () -> O { return mkbImpl() }
          for mkbTargetBox in self.mockingbirdContext.proxy.targets(for: $0) {
            switch mkbTargetBox.target {
            case .super:
              break
            case .object:
              break
            }
          }
          if let mkbValue = self.mockingbirdContext.stubbing.defaultValueProvider.value.provideValue(for: (O).self) { return mkbValue }
          self.mockingbirdContext.stubbing.failTest(for: $0, at: self.mockingbirdContext.sourceLocation)
        }
      }
    
      public func `map`(`i`: @autoclosure () -> I) -> Mockingbird.Mockable<Mockingbird.FunctionDeclaration, (I) -> O, O> {
        return Mockingbird.Mockable<Mockingbird.FunctionDeclaration, (I) -> O, O>(context: self.mockingbirdContext, invocation: Mockingbird.SwiftInvocation(selectorName: "`map`(`i`: I) -> O", selectorType: Mockingbird.SelectorType.method, arguments: [Mockingbird.resolve(`i`)], returnType: Swift.ObjectIdentifier((O).self)))
      }
    }
    
    public enum Mapper<I, O> {
    }
    /// Returns a concrete mock of `Mapper`.
    public func mock<I, O>(_ type: Mapper<I, O>.Type, file: StaticString = #file, line: UInt = #line) -> MapperMock<I, O> {
      return MapperMock<I, O>(sourceLocation: Mockingbird.SourceLocation(file, line))
    }
    
    

    Error

    Type 'MapperMock<I, O>' does not conform to protocol 'Mapper'

    Environment

    • Mockingbird version: 0.20.0
    • Xcode and Swift version: 14.0.1 and 5.7
    • Package manager: CocoaPods
    • Unit testing framework: XCTest
    generator bug 
    opened by mecoFarid 0
  • forwardCallsToSuper on class method

    forwardCallsToSuper on class method

    New Feature Request Checklist

    Overview

    I am wondering how to stub as a partial mock on class method, just like

    let bird = type(of: mock(Bird.self))
    bird.forwardCallsToSuper()
    

    But i found the forwardCallsToSuper is only instance method in Mock extension

    public extension Mock {
        @discardableResult
        func forwardCallsToSuper() -> Self {
            mockingbirdContext.proxy.addTarget(.super)
            return self
        }
    }
    

    Can i add the static method forwardCallsToSuper in Mock extension ?

    public extension Mock {
        @discardableResult
        func forwardCallsToSuper() -> Self {
            mockingbirdContext.proxy.addTarget(.super)
            return self
        }
    
        @discardableResult
        static func forwardCallsToSuper() -> Self.Type {
            mockingbirdContext.proxy.addTarget(.super)
            return self
        }
    }
    
    enhancement 
    opened by Zzz-Du 0
  • Fix parsing of unrecognized attributes

    Fix parsing of unrecognized attributes

    Fixes #310

    Overview

    If Mockingbird encounters an unrecognized attribute, it gets stuck in an infinite loop. Although this was first noticed with @Sendable, the introduction of global actors means that there may be arbitrary attributes which are unknowable to the generator.

    This PR fixes the behavior when encountering an unrecognized attribute, so that the generator no longer gets stuck.

    Test Plan

    I added a test case which uses @NotARealAttribute to test that the parser skips over unrecognized attributes.

    opened by bbrk24 0
  • warning: no calls to throwing functions occur within 'try'

    warning: no calls to throwing functions occur within 'try'

    New Issue Checklist

    • [x] I updated the framework and generator to the latest version
    • [x] I searched the existing GitHub issues and list of common problems
    • [x] I searched google for related issues/solutions

    Overview

    Constantly recieve warnings when trying to verify a call that can throw: warning: no calls to throwing functions occur within 'try' expression

    Example

    Protocol as such:

    public protocol Fetchable {
        func fetch(data: Dictionary<String, Any>) throws -> Task<[String: Any], Error>
    }
    

    Mocked as such:

    let JsonFetcher = mock(Fetchable.self)
    

    Tested:

    given(try! JsonFetcher.fetch(data: any())).willReturn(Task {[:]})
    _ = try! JsonFetcher.fetch(data: [:])
    verify(try JsonFetcher.fetch(data: any())).wasCalled()
    

    For both (given & verify) lines in the test, warnings are generated:

    warning: no calls to throwing functions occur within 'try' expression
                    given(try! JsonFetcher.fetch(data: any())).willReturn(Task {
    

    and

    warning: no calls to throwing functions occur within 'try' expression
                        verify(try JsonFetcher.fetch(data: any())).wasCalled()
    

    Expected Behavior

    No warnings

    Environment

    • Mockingbird CLI version (mockingbird version)
    Using Mockingbird v0.20.0
    0.20.0
    
    • Xcode and Swift version (swift --version)
    swift-driver version: 1.62.8 Apple Swift version 5.7 (swiftlang-5.7.0.127.4 clang-1400.0.29.50)
    Target: x86_64-apple-macosx12.0
    
    • Package manager (CocoaPods, Carthage, SPM project, SPM package) SPM package
    • Unit testing framework (XCTest, Quick/Nimble) Both XCTest and Quick/Nimble exhibit the issue.
    • Custom configuration
      • [x] Mockingbird ignore files - none
      • [x] Supporting source files - see above
    framework bug 
    opened by lwoydziak 0
Releases(0.20.0)
  • 0.20.0(Jan 29, 2022)

    Targets

    Framework

    • Xcode 12.5+ / Swift 5.4+
    • iOS 9.0+, macOS 10.10+, tvOS 9.0+, watchOS 7.4+

    Generator

    • macOS 10.15+

    Migrating from 0.19

    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
    

    New Features

    Test async methods

    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()
    

    Verify initializers

    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()
    

    Enhancements

    • Improved the static mocking APIs and documentation (#287) @andrewchang-bird
    • Fixed handling of read-only subscripts (#285) @andrewchang-bird | @logicxd
    • Added the ability to mock sources in test bundles (#286) @andrewchang-bird | Karl
    • Fixed cache invalidation when generating mocks for targets outside of the test target’s project context (#278) @andrewchang-bird
    • Fixed handling of optional members in Objective-C protocols (#279) @andrewchang-bird
    Source code(tar.gz)
    Source code(zip)
    Mockingbird.doccarchive.zip(1.99 MB)
    Mockingbird.xcframework.zip(31.94 MB)
    Mockingbird.zip(19.49 MB)
    MockingbirdSupport.zip(5.06 KB)
  • 0.19.2(Jan 20, 2022)

    Patch Notes

    • Fixed pre-built library evolution and testability (#265) Andrew Chang | ugomarinelli
    • Fixed stubbing nested optional properties and Objective-C members (#274) Andrew Chang
    • Improved compile-time checks for stubbing Swift methods (#273) Andrew Chang
    • Removed Objective-C based nil check (#272) Andrew Chang | Ian Keen
    • Cleaned up Synchronized wrapper (#275) Andrew Chang
    Source code(tar.gz)
    Source code(zip)
    Mockingbird.doccarchive.zip(1.99 MB)
    Mockingbird.xcframework.zip(31.75 MB)
    Mockingbird.zip(19.49 MB)
    MockingbirdSupport.zip(5.06 KB)
  • 0.19.1(Jan 8, 2022)

  • 0.19.0(Jan 8, 2022)

    Targets

    Framework

    • Xcode 13.2 / Swift 5.5.2
    • iOS 9.0+, macOS 10.10+, tvOS 9.0+, watchOS 7.4+

    Generator

    • macOS 10.15+

    Migrating from 0.18

    Re-configure SwiftPM projects

    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.

    Switch to the configure command

    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.

    New Features

    Configurator

    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!
    

    Revamped Documentation

    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.

    Enhancements

    • Fixed wildcard argument matching for Objective-C parameter types (#247) Andrew Chang | jdschin
    • Optimized dependency graph traversal for JSON project descriptions (#249) Andrew Chang | Jonathan Ueki
    • Fixed stubbing nil values on Objective-C mocks implicitly bridging to NSNull (#246) Andrew Chang | molenick-mov | Bohdan Orlov
    • Fixed nested optional codegen causing warnings about implicit type coercion to Any? (#248) Andrew Chang | Bohdan Orlov
    • Fixed cache invalidation when generating mocks for a source target in a different Xcode project (#250) Andrew Chang | Muzammil Mahmood
    • Fixed unavailable generic protocol mock initializer codegen (#251) Andrew Chang | Luke
    • Replaced SwiftPM argument parsing utils with Swift Argument Parser (#245) Andrew Chang
    • Added help message to file when no mockable types are generated (#252) Andrew Chang
    • Refactored build automation pipeline (#256) Andrew Chang
    Source code(tar.gz)
    Source code(zip)
    Mockingbird.doccarchive.zip(1.93 MB)
    Mockingbird.zip(19.49 MB)
    MockingbirdSupport.zip(5.06 KB)
  • 0.18.0(Aug 20, 2021)

    Targets

    • Xcode 12.5 / Swift 5.4
    • iOS 9.0+, macOS 10.14+, tvOS 9.0+

    New Features

    Mocking Objective-C Types

    This 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()
    

    Partial Mocks (Spies)

    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()
    

    Property Accessor Syntax

    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 /* ... */ }
    

    Enhancements

    Source code(tar.gz)
    Source code(zip)
    Mockingbird-cisafe.zip(13.43 MB)
    Mockingbird.pkg(13.43 MB)
    Mockingbird.zip(13.43 MB)
    MockingbirdSupport.zip(5.27 KB)
  • 0.17.0(Jul 27, 2021)

    Targets

    • Xcode 12.5 / Swift 5.4
    • iOS 8.0+, macOS 10.14+, tvOS 9.0+

    Migrating from 0.16

    Versioned CLI

    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:

    • CocoaPods: Pods/MockingbirdFramework/mockingbird generate ...
    • Carthage: Carthage/Checkouts/mockingbird generate ...
    • Swift Package Manager:
    DERIVED_DATA="$(echo "${OBJROOT}" | pcregrep -o1 '(/.*)/Build')"
    REPO_PATH="${DERIVED_DATA}/SourcePackages/checkouts/mockingbird"
    "${REPO_PATH}/mockingbird" generate ...
    

    Thunk Pruning

    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. |

    New Features

    • Added ability to specify asset bundle download URL (#201) ynx-zeissl
    • Added versioned CLI launcher (#202) Andrew Chang
    • Added support for imports gated by compilation directives (#205) Andrew Chang
    • Changed custom headers to fully replace the default header (#210) Andrew Chang
    • Added support for parsing project descriptions from Swift Package Manager (#215) Kiel Gillard

    Enhancements

    • Fixed cache invalidation from multiple tests using the same lock file (#193) Péter Szabolcs Nagy
    • Fixed path processing bug for CI safe binaries run from a symlink (#196) Steven Hocking
    • Bumped Swift Syntax version to 5.4 for Xcode 12.5 (#204) Andrew Chang
    • Changed default thunk pruning level from 'stub' to 'omit' (#206) Andrew Chang
    • Removed incorrect mocking of methods in protocol extensions (#207) Andrew Chang
    • Improved parsing of function parameter attributes (#208) Andrew Chang
    • Updated Carthage integration tests to support Xcode 12 with XCFrameworks (#209) Andrew Chang
    Source code(tar.gz)
    Source code(zip)
    Mockingbird-cisafe.zip(12.21 MB)
    Mockingbird.pkg(12.22 MB)
    Mockingbird.zip(12.21 MB)
    MockingbirdSupport.zip(5.27 KB)
  • 0.16.0(Oct 8, 2020)

    Targets

    • Xcode 12.0 / Swift 5.3
    • iOS 8.0+, macOS 10.14+, tvOS 9.0+

    Migrating from 0.15

    Thunk Pruning

    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. |

    New Features

    • Added the ability to pass ad hoc JSON project descriptions to the generator instead of a .xcodeproj file (#171) Andrew Chang
    • Added a thunk pruning option to fully exclude unused types from generating thunks (#174) Andrew Chang
    • Added support for setting GH_ACCESS_TOKEN to address rate limiting when downloading prebuilt binaries (#169) Andrew Chang

    Enhancements

    • Improved support for Xcode 12 / Swift 5.3 and upgraded all dependency versions (#168) Andrew Chang
    • Improved handling of module names shadowed by top level nominal types (#172) Andrew Chang
    Source code(tar.gz)
    Source code(zip)
    Mockingbird-cisafe.zip(12.66 MB)
    Mockingbird.pkg(12.65 MB)
    Mockingbird.zip(12.66 MB)
    MockingbirdSupport.zip(5.27 KB)
  • 0.15.0(Aug 13, 2020)

    Targets

    • Xcode 11.6 / Swift 5.2
    • iOS 8.0+, macOS 10.14+, tvOS 9.0+

    Migrating from 0.14

    Generic Mock Initialization

    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 Semantics

    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)
    

    New Features

    Enhancements

    • Updated code signing certificates and added CI action to build signed artifacts on commit with audit trail (#104) Andrew Chang | Ryan Meisters
    Source code(tar.gz)
    Source code(zip)
    Mockingbird-cisafe.zip(11.54 MB)
    Mockingbird.pkg(11.53 MB)
    Mockingbird.zip(11.54 MB)
    MockingbirdSupport.zip(6.07 KB)
  • 0.14.1(Jul 30, 2020)

  • 0.14.0(Jul 15, 2020)

    Targets

    • Xcode 11.5 / Swift 5.2
    • iOS 8.0+, macOS 10.14+, tvOS 9.0+

    Migrating from 0.13

    Thanks to Joe Tennant and various partners for testing this month’s 0.14 release candidate. If you’d like to help with a future release or add your project to Mockingbird’s source compatibility tests, please reach out on Slack.

    Explicit Stubbing Syntax

    To make the framework more accessible to all users, this release introduces an explicit stubbing syntax that uses named methods instead of global operators. Although the explicit stubbing syntax will be the default in documentation going forward, the ~> stubbing operator will continue to exist as the shorthand notation.

    The explicit stubbing syntax is a 1:1 match with the stubbing operator, so switching between the two notations is very intuitive.

    // Explicit stubbing syntax
    given(bird.canChirp()).willReturn(true)
    given(bird.canChirp()).willThrow(BirdError())
    given(bird.canChirp(volume: any())).will { volume in
      return volume < 42
    }
    
    // Shorthand stubbing operator
    given(bird.canChirp()) ~> true
    given(bird.canChirp()) ~> { throw BirdError() }
    given(bird.canChirp(volume: any())) ~> { volume in
      return volume < 42
    }
    

    As part of the explicit stubbing syntax addition, this release also includes an API reference generated from HeaderDoc comments: https://birdrides.github.io/mockingbird/latest/

    Fast Compilation with Thunk Stubs

    To reduce compilation time, Mockingbird now only generates mocking code (known as thunks) for types referenced in tests with mock(SomeType.self). Types not used in any test files produce minimal generated code in the form of “thunk stubs,” which are simply bodies containing fatalError. Projects that indirectly synthesize mocked types, such as through Objective-C based dependency injection, may incorrectly encounter thunk stubs during tests and require special consideration.

    • Option 1: Explicitly reference each indirectly synthesized type in your tests, e.g. _ = mock(SomeType.self). References can be placed anywhere in the test target sources, such as in the setUp method of a test case or in a single file.
    • Option 2: Disable thunk stubs entirely by adding the --disable-thunk-stubs generator flag.

    New Features

    Enhancements

    • Fixed regression in recording throwing invocations (#148) Andrew Chang | Joe Tennant
    • Improved missing stub implementation test failure message by including invocation stack trace and examples (#142) Andrew Chang
    • Fixed missing return type in ordering logic (#145) Andrew Chang
    • Improved SPM installation instructions (#147) Andrew Chang
    • Improved documentation for class mocks and unavailable mocks (#149) Andrew Chang
    Source code(tar.gz)
    Source code(zip)
    Mockingbird.pkg(11.62 MB)
    Mockingbird.zip(11.83 MB)
    MockingbirdSupport.zip(6.07 KB)
  • 0.13.1(Jun 23, 2020)

  • 0.13.0(Jun 9, 2020)

    Targets

    • Xcode 11.4 / Swift 5.2
    • iOS 8.0+, macOS 10.14+, tvOS 9.0+

    Migrating from 0.12

    • Mocks for types without designated initializers and conforming to NSObjectProtocol now correctly inherit the designated initializer from NSObject and must be initialized with .initialize()
    protocol MyProtocol: NSObjectProtocol {}
    
    // Old
    mock(MyProtocol.self)
    
    // New
    mock(MyProtocol.self).initialize()
    

    New Features

    • Added ability to provide wildcard generic Swift types in a ValueProvider (#122) Andrew Chang | Ryan Meisters
    • Added support for stubbing a sequence of implementations using closures (#120) Andrew Chang | Luke

    Enhancements

    Source code(tar.gz)
    Source code(zip)
    Mockingbird.pkg(8.50 MB)
    Mockingbird.zip(8.71 MB)
    MockingbirdSupport.zip(6.07 KB)
  • 0.12.2(May 27, 2020)

  • 0.12.0(May 7, 2020)

    Targets

    • Xcode 11.4 / Swift 5.2
    • iOS 8.0+, macOS 10.14+, tvOS 9.0+

    Migrating from 0.11

    • Mocking class constrained protocols without designated initializers now uses protocol mocking instead of class mocking
    protocol MyProtocol: AnyObject {}
    
    // Old
    mock(MyProtocol.self).initialize()
    
    // New
    mock(MyProtocol.self)
    
    • The convenience non-parameterized closure stubbing operator has been removed; convert implicit argument closure stubs to explicitly ignore arguments
    // Old
    given(myMock.doSomething(with: any())) ~> { print("Ignoring arguments") }
    
    // New
    given(myMock.doSomething(with: any())) ~> { _ in print("Ignoring arguments") }
    

    New Features

    • Add ability to provide default values for unstubbed methods (#80) Andrew Chang | Sterling Hackley | Ryan Meisters
    • Add support for diagnostic warnings and errors that integrate with Xcode’s buildtime issues in the sidebar (#102) Andrew Chang
    • Add asset download command to improve supporting source file setup, usage $ mockingbird download starter-pack (#101) Andrew Chang
    • Add sequential stubbing for returning a sequence of predefined values (#90) Andrew Chang
    • Add support for stubbing and verifying subscripts (#89) Andrew Chang | Pavel Ivashkov

    Enhancements

    • Refactor import and compilation directive parsing to use SwiftSyntax, resulting in faster code generation (#92) Andrew Chang
    • Uniquify default generated file names when using the installer by prefixing the test target name (#100) Andrew Chang

    Bug Fixes

    • Fix compatibility with Swift 5.2 (#91) Andrew Chang
    • Fix stubbing methods without parameters by removing the non-parameterized closure stubbing operator (#86) Andrew Chang | seven332
    • Fix generating convenience initializers for class constrained protocols without a declared designated initializer Andrew Chang
    • Fix handling bash-style variables in build settings, e.g. ${TARGET_NAME} (#83) Andrew Chang
    • Fix type inference for string literals and initialized types assigned to properties in class mocks (#108) Andrew Chang | Ryan Meisters
    • Fix mocking classes with designated and synthesized initializers, e.g. from Decodable (#93) Andrew Chang | Tristan Diependael
    • Fix synchronization of collection types in CLI and framework (#106) Andrew Chang
    • Fix uninstaller not removing .generated.swift source files added by the installer (#100) Andrew Chang
    Source code(tar.gz)
    Source code(zip)
    Mockingbird.pkg(7.71 MB)
    Mockingbird.zip(7.82 MB)
    MockingbirdSupport.zip(5.27 KB)
  • 0.11.1(Apr 10, 2020)

  • 0.11.0(Apr 8, 2020)

    Note: Because the generator in the 0.11.1 patch is compatible with 0.11.0, we’ve backported all artifacts from 0.11.1 into this release.

    Targets

    • Xcode 11.3 / Swift 5.1
    • iOS 8.0+, macOS 10.14+, tvOS 9.0+

    Breaking

    • Enforce correct usage of class and protocol mocks by showing compile time errors when coercing mocks or using uninitialized class mocks. Use dummy(SomeType.self) instead of mock(SomeType.self) when passing initialized test objects as arguments that don’t require mocking or stubbing Andrew Chang
    • Change CLI install command parameter names from mockingbird install --target Bird --destination BirdTests to mockingbird install --target BirdTests --source Bird Andrew Chang
    • Improve Carthage installation process to work when directly running $ carthage update Andrew Chang

    Experimental

    • None

    Enhancements

    • Add in order verification for enforcing relative invocation ordering Andrew Chang
    • Support implicitly imported modules in mixed-source (Objective-C and Swift) targets Andrew Chang
    • Handle negation and non-relative patterns in .mockingbird-ignore files Andrew Chang
    • Add CocoaPods and Carthage example projects and integration tests Andrew Chang
    • Improve integration of nominal count matchers, allowing for syntax like verify(foo.bar()).wasCalled(once) and verify(foo.bar()).wasCalled(atLeast(once)) Andrew Chang
    • Add fuzzy floating point argument matcher to standard testing library, usage: around(10.0, tolerance: 0.01) Andrew Chang
    • Improve clarity and verboseness of test failure messages, showing invocation history Andrew Chang
    • Add CustomStringConvertible to standard supporting source files Andrew Chang
    • Improve clarity of setup and installation process in README, including a new Troubleshooting section Andrew Chang
    • Include prebuilt iOS, macOS, and tvOS frameworks in release artifacts Andrew Chang

    Bug Fixes

    • Support implicit TARGET_NAME build setting for module name resolution Andrew Chang
    • Specialize members inherited from generic classes Andrew Chang
    • Fix type coercion regression in type facade resolution method which was erasing type annotations Andrew Chang
    • Fix parsing optional function return types Andrew Chang
    • Handle class-constrained protocols with designated initializers Andrew Chang
    • Handle generic type shadowing top-level types and other generic types Andrew Chang
    Source code(tar.gz)
    Source code(zip)
    Mockingbird.pkg(4.22 MB)
    Mockingbird.zip(4.33 MB)
    MockingbirdCli.pkg(2.28 MB)
    MockingbirdCli.zip(2.28 MB)
    MockingbirdSupport.zip(6.25 KB)
  • 0.10.0(Feb 28, 2020)

    Breaking

    • None

    Experimental

    • None

    Enhancements

    • Improve handling of members imported from external modules Andrew Chang
    • Improve handling of types and constraints inherited from grandparents Andrew Chang
    • Use path prefix for CLI binary installation Pavel Ivashkov
    • Add MockingbirdCli as a dependency to MockingbirdTests Pavel Ivashkov
    • Parse and handle parenthesized expressions separately from tuples Andrew Chang
    • Log warning when trying to mock a non-initializable class Andrew Chang
    • Improve target module name resolving Andrew Chang

    Bug Fixes

    • Fix interleaving of log output by manually flushing Andrew Chang
    • Rewrite type facade to use execution context approach for improved stability Andrew Chang
    • Add support for reserved keyword parameter names by escaping Ryan Meisters
    • Match dot files with a wildcard in ignore rules Pavel Ivashkov
    • Ignore objc attributes for all generated hooks Andrew Chang
    Source code(tar.gz)
    Source code(zip)
    Mockingbird.pkg(2.27 MB)
    Mockingbird.zip(2.35 MB)
    MockingbirdCli.pkg(2.27 MB)
    MockingbirdCli.zip(2.35 MB)
    MockingbirdSupport.zip(5.03 KB)
  • 0.9.0(Dec 3, 2019)

    Breaking

    • Remove automatic binary installation from pod install prepare_command. Not all environments (e.g. CI) allow modifying /usr/local/bin. Run $ make install-prebuilt as needed to set up your environment. Andrew Chang

    Experimental

    • None

    Enhancements

    • None

    Bug Fixes

    • Invalidate cached mocked modules when the CLI version changes Andrew Chang
    • Gather module names for inherited types Alvar Hansen
    • Include declarations in extensions when flattening inherited types Andrew Chang
    • Fix matching closures with wildcard argument matchers Andrew Chang
    Source code(tar.gz)
    Source code(zip)
    MockingbirdCli.pkg(2.26 MB)
    MockingbirdCli.zip(2.34 MB)
  • 0.8.0(Nov 1, 2019)

    Breaking

    • None

    Experimental

    • Add per-module caching of generated mocks to reduce the overhead in reading large Xcode project files Andrew Chang

    Enhancements

    • Improve CLI error messaging (https://github.com/birdrides/mockingbird/pull/11) Sterling Hackley
    • Improve support for mocking classes conforming to built-in Swift protocols with implicitly required initializers such as Decodable Andrew Chang
    • Improve handling of imports and compilation directives within comment blocks and string literals Andrew Chang
    • Add loglevel option to the CLI installer to specify a logging level to use when generating mocks Andrew Chang

    Bug Fixes

    • Fix fnmatch implementation on macOS Catalina (https://github.com/birdrides/mockingbird/pull/15) Andrew Chang
    • Remove generic type alphabetization (https://github.com/birdrides/mockingbird/pull/14) Andrew Chang
    • Handle non-alphanumeric target names (https://github.com/birdrides/mockingbird/pull/10) Sterling Hackley
    • Fix class-only protocol initializer generation (https://github.com/birdrides/mockingbird/pull/9) Andrew Chang
    • Fix handling of failable initializers with generic type constraints Andrew Chang
    Source code(tar.gz)
    Source code(zip)
    MockingbirdCli.pkg(2.25 MB)
    MockingbirdCli.zip(2.33 MB)
  • 0.7.0(Sep 23, 2019)

    Breaking

    • None

    Experimental

    • None

    Enhancements

    Bug Fixes

    Source code(tar.gz)
    Source code(zip)
    MockingbirdCli.pkg(2.20 MB)
    MockingbirdCli.zip(2.28 MB)
  • 0.6.1(Sep 18, 2019)

  • 0.6.0(Sep 17, 2019)

    Notes

    This is a quiet release of Mockingbird to gather initial developer feedback before the full rollout next week.

    Breaking

    • Rename --src-targets to --targets in the CLI installer for simplicity Andrew Chang

    Experimental

    • Flag mocked types that inherit unparsed types, such as from the Swift standard library and auto-generate conformance for common Self constrained protocols in the Swift standard library Andrew Chang

    Enhancements

    • Add --verbose and --quiet logging options to CLI Andrew Chang
    • Add CI support to the repo using GitHub Actions which builds, installs, and tests the framework and CLI Andrew Chang
    • Return an exit status code of 1 when a fatal CLI error occurs Andrew Chang
    • Refactor mock generation pipeline rendering step for improved semantics and clarity Andrew Chang
    • Improve TypeFacade synchronization implementation Andrew Chang

    Bug Fixes

    • Fix incorrect counting of invocations for overloaded methods Andrew Chang
    • Fix incorrect type qualification level for types which could be shadowed by types defined in external modules Andrew Chang
    • Fix mocking types that inherit types with non-public initializers defined in external modules Andrew Chang
    • Fix inherited associated type protocols and Self constrained protocols that require type qualification Andrew Chang
    • Fix conformance-based generic where clauses and type qualification of generic where clauses Andrew Chang
    • Fix support for rethrowing methods Andrew Chang
    • Fix mocking empty types with conformance or inheritance Andrew Chang
    • Fix incorrect de-duplication of inherited members in class mocks Andrew Chang
    Source code(tar.gz)
    Source code(zip)
    MockingbirdCli.pkg(2.19 MB)
    MockingbirdCli.zip(2.24 MB)
  • 0.5.0(Sep 14, 2019)

    Breaking

    • None

    Experimental

    • None

    Enhancements

    • Add support for using a .mockingbird-ignore file to exclude sources or source directories from being mocked Andrew Chang
    • Make mockingbird install fully set up a unit test target by accepting explicit source and destination targets, --src-targets and --destination respectively Andrew Chang
    • Support os.log signposts for improved instrumentation when using Instruments.app Andrew Chang
    • Improve CLI error handling for malformed or missing arguments Andrew Chang
    • Allow binary pinning by not removing prebuilt binary when running make install-prebuilt Andrew Chang
    • Improve performance when writing generated mock files with many mocked types Andrew Chang
    • Improve performance of running type specialization on types that don’t require specialization Andrew Chang
    • Add GitHub report issue template Andrew Chang
    • Add instructions on how to link Mockingbird to a unit test target when building from source Andrew Chang

    Bug Fixes

    • Fix parsing non-open declarations in external modules Andrew Chang
    Source code(tar.gz)
    Source code(zip)
    MockingbirdCli.pkg(2.15 MB)
    MockingbirdCli.zip(2.20 MB)
  • 0.4.0(Sep 10, 2019)

    Breaking

    • Update mock initialization API for classes; mock(SomeClassWithoutInitializers.self) and mock(SomeClassWithInitializers.self).initialize(...) Andrew Chang
    • Make Mockingbird CLI installer use synchronous generation by default and rename --synchronous option to --asynchronous Andrew Chang

    Experimental

    • None

    Enhancements

    • Improve generator performance and reduce generated code length, see Performance.md for benchmarks Andrew Chang
    • Uniquify generated accessor methods so that it cannot conflict with original methods that have the same function signature Andrew Chang
    • Remove ability to directly create protocol mocks using init(sourceLocation:) Andrew Chang

    Bug Fixes

    • Fix type qualification system not searching all imported modules Andrew Chang
    • Fix support for mocking and stubbing stored variables in classes Andrew Chang
    • Fix nested classes not able to be initialized with the new mock initialization system Andrew Chang
    • Fix support for implicitly unwrapped types Andrew Chang
    Source code(tar.gz)
    Source code(zip)
    MockingbirdCli.pkg(2.14 MB)
    MockingbirdCli.zip(2.19 MB)
  • 0.3.0(Sep 7, 2019)

    Breaking

    • Improve mock initialization API for consistency between protocols and classes; mock(SomeProtocol.self) and mock(SomeClass.self).init(...) Andrew Chang
    • Remove chained stubbing to simplify generated code and DSL Andrew Chang
    • Remove multi verification of invocations with the same return type to simplify DSL Andrew Chang

    Experimental

    • None

    Enhancements

    Bug Fixes

    • Fix support for throwing and failable initializers Andrew Chang
    Source code(tar.gz)
    Source code(zip)
    MockingbirdCli.pkg(2.12 MB)
    MockingbirdCli.zip(2.17 MB)
  • 0.2.0(Sep 3, 2019)

    Breaking

    • Add mockProtocol(SomeProtocol.self) and mockClass(instance: SomeClassMock()) mock initializers, replacing the previous unwrapped SomeProtocolMock() and SomeClassMock() mock initialization method. Andrew Chang

    Experimental

    • None

    Enhancements

    • Add new type system for parsing indirect typealiasing, tuples, collection literals, function types, and fully qualifying referenced types (by prefixing with module and scope names) Andrew Chang
    • Add ability to stub nested mocks using chained stubbing operator Andrew Chang
    • Add version command to CLI Andrew Chang
    • Remove generated date from generated mock file header comments Andrew Chang

    Bug Fixes

    • Fix “no stubbed invocation” errors stopping tests when using XCTestCase wrappers like Quick and Nimble Andrew Chang
    Source code(tar.gz)
    Source code(zip)
    MockingbirdCli.pkg(2.12 MB)
    MockingbirdCli.zip(2.16 MB)
  • 0.1.3(Aug 28, 2019)

  • 0.1.1(Aug 26, 2019)

  • 0.1.0(Aug 26, 2019)

Mockit is a Tasty mocking framework for unit tests in Swift 5.0

Mockit Introduction Mockit is a Tasty mocking framework for unit tests in Swift 5.0. It's at an early stage of development, but its current features a

Syed Sabir Salman-Al-Musawi 118 Oct 17, 2022
A mocking framework for Swift

SwiftMock SwiftMock is a mocking framework for Swift 5.2. Notes on the history of this repo September 2015: first version of this framework November 2

Matthew Flint 257 Dec 14, 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
Efs - Easy function mocking/stubbing in Swift

Efs Efs, as the pronounced plural of letter F (for function), is a simple mockin

Jérémy Touzy 0 Feb 12, 2022
Mockingbird was designed to simplify software testing, by easily mocking any system using HTTP/HTTPS

Mockingbird Mockingbird was designed to simplify software testing, by easily mocking any system using HTTP/HTTPS, allowing a team to test and develop

FARFETCH 183 Dec 24, 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
XCTestExtensions is a Swift extension that provides convenient assertions for writing Unit Test.

XCTestExtensions Features XCTAssertEventually (that convenient assertions for writing Unit Test). Use "XCTAssertEventually", you can write asynchronou

shindyu 22 Dec 1, 2022
A Matcher Framework for Swift and Objective-C

Nimble Use Nimble to express the expected outcomes of Swift or Objective-C expressions. Inspired by Cedar. // Swift expect(1 + 1).to(equal(2)) expect(

Quick 4.6k Dec 31, 2022
The Swift (and Objective-C) testing framework.

Quick is a behavior-driven development framework for Swift and Objective-C. Inspired by RSpec, Specta, and Ginkgo. // Swift import Quick import Nimbl

Quick 9.6k Dec 31, 2022
BDD Framework and test runner for Swift projects and playgrounds

Spectre Special Executive for Command-line Test Running and Execution. A behavior-driven development (BDD) framework and test runner for Swift project

Kyle Fuller 392 Jan 1, 2023
AutoMocker is a Swift framework that leverages the type system to let you easily create mocked instances of your data types.

AutoMocker Context AutoMocker is a Swift framework that leverages the type system to let you easily create mocked instances of your data types. Here's

Vincent Pradeilles 39 May 19, 2022
BDD-style framework for Swift

Sleipnir Sleipnir is a BDD-style framework for Swift. Sleipnir is highly inspired by Cedar. Also In Norse mythology, Sleipnir is Odin's steed, is the

Railsware 846 Nov 22, 2022
Swift Framework for TestRail's API

QuizTrain ?? ?? QuizTrain is a framework created at Venmo allowing you to interact with TestRail's API using Swift. It supports iOS, macOS, tvOS, and

Venmo 18 Mar 17, 2022
Swift framework containing a set of helpful XCTest extensions for writing UI automation tests

AutoMate • AppBuddy • Templates • ModelGenie AutoMate AutoMate is a Swift framework containing a set of helpful XCTest extensions for writing UI autom

PGS Software 274 Dec 30, 2022
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
Genything is a framework for random testing of a program properties.

Genything is a framework for random testing of a program properties. It provides way to random data based on simple and complex types.

Just Eat Takeaway.com 25 Jun 13, 2022
A light-weight TDD / BDD framework for Objective-C & Cocoa

Specta A light-weight TDD / BDD framework for Objective-C. FEATURES An Objective-C RSpec-like BDD DSL Quick and easy set up Built on top of XCTest Exc

Specta / Expecta 2.3k Dec 20, 2022
Switchboard - easy and super light weight A/B testing for your mobile iPhone or android app. This mobile A/B testing framework allows you with minimal servers to run large amounts of mobile users.

Switchboard - easy A/B testing for your mobile app What it does Switchboard is a simple way to remote control your mobile application even after you'v

Keepsafe 287 Nov 19, 2022
Remote configuration and A/B Testing framework for iOS

MSActiveConfig v1.0.1 Remote configuration and A/B Testing framework for iOS. Documentation available online. MSActiveConfig at a glance One of the bi

Elevate 78 Jan 13, 2021