Failing to infer mocked type
paiv opened this issue · comments
Pavel Ivashkov commented
New Issue Checklist
- I updated my Mockingbird framework and CLI to the latest version
- I searched for existing GitHub issues
Description
Inferred return type of mock()
is not usable.
Generator Bugs
$ mockingbird generate \
--only-protocols \
--disable-cache \
--targets 'Sample' \
--outputs "${SRCROOT}/MockingbirdMocks/SampleMocks.generated.swift"
- A minimal example of the original source
protocol Bird {
func fly()
}
- The actual mocking code generated
//
// SampleMocks.generated.swift
// Sample
//
// Generated by Mockingbird v0.11.0.
// DO NOT EDIT
//
@testable import Mockingbird
@testable import Sample
import Foundation
import Swift
private var genericTypesStaticMocks = Mockingbird.Synchronized<[String: Mockingbird.StaticMock]>([:])
// MARK: - Mocked Bird
public final class BirdMock: Sample.Bird, Mockingbird.Mock, BirdAbstractMockType {
static let staticMock = Mockingbird.StaticMock()
public let mockingContext = Mockingbird.MockingContext()
public let stubbingContext = Mockingbird.StubbingContext()
public let mockMetadata = Mockingbird.MockMetadata(["generator_version": "0.11.0", "module_name": "Sample"])
public var sourceLocation: Mockingbird.SourceLocation? {
get { return stubbingContext.sourceLocation }
set {
stubbingContext.sourceLocation = newValue
BirdMock.staticMock.stubbingContext.sourceLocation = newValue
}
}
fileprivate init(sourceLocation: Mockingbird.SourceLocation) {
Mockingbird.checkVersion(for: self)
self.sourceLocation = sourceLocation
}
// MARK: Mocked `fly`()
public func `fly`() -> Void {
let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`fly`() -> Void", arguments: [])
mockingContext.didInvoke(invocation)
let implementation = stubbingContext.implementation(for: invocation, optional: true)
if let concreteImplementation = implementation as? () -> Void {
concreteImplementation()
} else {
(implementation as? () -> Void)?()
}
}
public func `fly`() -> Mockingbird.Mockable<Mockingbird.MethodDeclaration, () -> Void, Void> {
let invocation: Mockingbird.Invocation = Mockingbird.Invocation(selectorName: "`fly`() -> Void", arguments: [])
return Mockingbird.Mockable<Mockingbird.MethodDeclaration, () -> Void, Void>(mock: self, invocation: invocation)
}
}
public protocol BirdAbstractMockType {}
/// Initialize a protocol mock of `Sample.Bird`.
public func mock(_ type: Sample.Bird.Protocol, file: StaticString = #file, line: UInt = #line) -> BirdAbstractMockType {
return BirdMock(sourceLocation: SourceLocation(file, line))
}
/// Initialize a protocol mock of `Sample.Bird`.
public func mock<__ReturnType: BirdAbstractMockType>(_ type: Sample.Bird.Protocol, file: StaticString = #file, line: UInt = #line) -> __ReturnType {
return BirdMock(sourceLocation: SourceLocation(file, line)) as! __ReturnType
}
/// Create a dummy object of `Sample.Bird`.
public func dummy(_ type: Sample.Bird.Protocol, file: StaticString = #file, line: UInt = #line) -> BirdMock {
return BirdMock(sourceLocation: SourceLocation(file, line))
}
/// Initialize a protocol mock of `Sample.Bird`.
@available(swift, obsoleted: 3.0, renamed: "dummy", message: "Store the mock in a variable of type 'BirdMock' or use 'dummy(Bird.self)' to create a non-mockable dummy object")
public func mock<__ReturnType>(_ type: Sample.Bird.Protocol) -> __ReturnType { fatalError() }
- The expected mocking code that should be generated (or a description)
Not sure yet.
Framework Bugs
Please provide a minimal example of your unit testing code, including any errors.
func testBird() {
let bird = mock(Bird.self)
(bird as Bird).fly()
// 'BirdAbstractMockType' is not convertible to 'Bird'; did you mean to use 'as!' to force downcast?
verify(bird.fly()).wasCalled()
// Value of type 'BirdAbstractMockType' has no member 'fly'
}
Environment
- Mockingbird CLI version
0.11.0
- Xcode
11.4
and macOS10.15.4
- Swift version
Apple Swift version 5.2 (swiftlang-1103.0.32.1 clang-1103.0.32.29)
- Installation method
CocoaPods
Pavel Ivashkov commented
This is unfortunate, and breaks README promise:
let bird: BirdMock = mock(Bird.self) // The concrete type is `BirdMock`
let inferredBird = mock(Bird.self) // but type inference also works
Andrew Chang commented
Thanks for reporting, this was an oversight on my part. Seems like there is no easy fix, so I’ll revert the initializer changes in 0.11.1
.
As a workaround, declaring explicit type annotations using the concrete mock type, e.g. SomeTypeMock
, should make the compiler happy again.