seanhenry / swiftmockgeneratorforxcode Goto Github PK
View Code? Open in Web Editor NEWAn Xcode extension (plugin) to generate Swift test doubles automatically.
License: MIT License
An Xcode extension (plugin) to generate Swift test doubles automatically.
License: MIT License
I've been trying to download releases of the project, but even though the dmg files are about 10 MB, I receive the error "no mountable file systems". This is the full verbose output in Terminal:
Initialising…
DIBackingStoreInstantiatorProbe: interface 0, score 100, CBSDBackingStore
DIBackingStoreInstantiatorProbe: interface 1, score -1000, CBundleBackingStore
DIBackingStoreInstantiatorProbe: interface 2, score -1000, CRAMBackingStore
DIBackingStoreInstantiatorProbe: interface 3, score 100, CCarbonBackingStore
DIBackingStoreInstantiatorProbe: interface 4, score -1000, CDevBackingStore
DIBackingStoreInstantiatorProbe: interface 5, score -1000, CCURLBackingStore
DIBackingStoreInstantiatorProbe: interface 6, score -1000, CVectoredBackingStore
Attaching…
2019-07-31 14:00:35.572 diskimages-helper[67732:9040372] -remountReturningDictionary: detaching because no mountable filesystems.
Error 112 (no mountable file systems).
Finishing…
DIHLDiskImageAttach() returned 112
hdiutil: attach failed - no mountable file systems
I tried downloading the project for compilation, but I'd need an older version of Xcode.
I read somewhere that if a dmg is too new for the OS, it won't recognise it. I am on Mojave 10.14.6.
If I generate a mock for the protocol like this
public typealias CompletionClosure = (() -> Void)
public protocol CustomTestType {
func async(completion: @escaping CompletionClosure)
}
I get the following mock:
class CustomTestMock: CustomTestType {
var invokedAsync = false
var invokedAsyncCount = 0
var invokedAsyncParameters: (completion: @escaping CompletionClosure, Void)?
var invokedAsyncParametersList = [(completion: @escaping CompletionClosure, Void)]()
func async(completion: @escaping CompletionClosure) {
invokedAsync = true
invokedAsyncCount += 1
invokedAsyncParameters = (completion, ())
invokedAsyncParametersList.append((completion, ()))
}
}
This can't be compiled due to "@escaping attribute may only be used in function parameter position"
For this protocol:
protocol MyClassProtocol {
func set(param1: Int, param2: Int)
}
It generates:
class MyClassMock: MyClassProtocol {
var invokedSet = false
var invokedSetCount = 0
var invokedSetParameters: (param1: Int, param2: Int)?
var invokedSetParametersList = [(param1: Int, param2: Int)]()
func set(param1: Int, param2: Int) {
invokedSet = true
invokedSetCount += 1
invokedSetParameters = (param1, param2)
invokedSetParametersList.append((param1, param2))
}
}
BUT if I add a second, similar method the mock for the first one changes:
protocol MyClassProtocol {
func set(param1: Int, param2: Int)
func set(param1: Int)
}
Generated code:
class MyClassMock: MyClassProtocol {
var invokedSetParam1 = false
var invokedSetParam1Count = 0
var invokedSetParam1Parameters: (param1: Int, param2: Int)?
var invokedSetParam1ParametersList = [(param1: Int, param2: Int)]()
func set(param1: Int, param2: Int) {
invokedSetParam1 = true
invokedSetParam1Count += 1
invokedSetParam1Parameters = (param1, param2)
invokedSetParam1ParametersList.append((param1, param2))
}
var invokedSet = false
var invokedSetCount = 0
var invokedSetParameters: (param1: Int, Void)?
var invokedSetParametersList = [(param1: Int, Void)]()
func set(param1: Int) {
invokedSet = true
invokedSetCount += 1
invokedSetParameters = (param1, ())
invokedSetParametersList.append((param1, ()))
}
}
Also, I think that mocks should reflect the FULL method signature to better comply with Swift conventions, resulting in something like this:
class MyClassMock: MyClassProtocol {
var invokedSetParam1Param2 = false
var invokedSetParam1Param2Count = 0
var invokedSetParam1Param2Parameters: (param1: Int, param2: Int)?
var invokedSetParam1Param2ParametersList = [(param1: Int, param2: Int)]()
func set(param1: Int, param2: Int) {
invokedSetParam1Param2 = true
invokedSetParam1Param2Count += 1
invokedSetParam1Param2Parameters = (param1, param2)
invokedSetParam1Param2ParametersList.append((param1, param2))
}
var invokedSetParam1 = false
var invokedSetParam1Count = 0
var invokedSetParam1Parameters: (param1: Int, Void)?
var invokedSetParam1ParametersList = [(param1: Int, Void)]()
func set(param1: Int) {
invokedSetParam1 = true
invokedSetParam1Count += 1
invokedSetParam1Parameters = (param1, ())
invokedSetParam1ParametersList.append((param1, ()))
}
}
I'm trying on Swift 5 and Xcode 10.2
I have followed instruction step by step, but in the end I couldn't see Mock Generator
in the Editor
menu. Could be the problem is with Xcode 10.2 only. With Xcode 10.1 everything worked fine.
Hi. I have switched to Xcode 11 GM and Mock Generator started to give me an error with message Could not find a class or protocol ...
. In Xcode 10.3 everything worked fine.
Hello,
I am having issues setting up Swift Mock Generator for Xcode
in System Preferences
: when I go to Security & Privacy
> Privacy
> Automation
, the app is not listed.
I have tried to reinstall the app, nothing changed.
Can you take a look at this issue?
Thank you!
macOS
version: macOS Mojave (10.14.6)
Xcode
versions: 10.3 and 11.1
Swift Mock Generator for Xcode
version: 0.23
Given a protocol like:
protocol MyProtocol {
var myObservable$: Observable<String> { get }
}
when I 'generate spy'
then the generated code does not contain stubs and spies for myObservable$
.
This used to work in earlier versions.
When code is generated it doesn’t set an access control to anything.
This raises a compiler error when both the protocol and the mock class are public/open.
For example, this protocol and class:
public protocol FooProtocol {
func bar(arg: String) -> Int
}
public class FooSpy: FooProtocol {
var invokedBar = false
var invokedBarCount = 0
var invokedBarParameters: (arg: String, Void)?
var invokedBarParametersList = [(arg: String, Void)]()
var stubbedBarResult: Int! = 0
func bar(arg: String) -> Int {
invokedBar = true
invokedBarCount += 1
invokedBarParameters = (arg, ())
invokedBarParametersList.append((arg, ()))
return stubbedBarResult
}
}
Protocols which contain generic functions can not be generated because the generic type can not be determined.
ex, this function:
`func getObjects<T: RealmSwift.Object>(_ objects: T.Type) -> Results<T>?`
Will generate as:
var invokedGetObjects = false
var invokedGetObjectsCount = 0
var invokedGetObjectsParameters: (objects: T.Type, Void)?
var invokedGetObjectsParametersList = [(objects: T.Type, Void)]()
var stubbedGetObjectsResult: Results<T>!
func getObjects<T: RealmSwift.Object>(_ objects: T.Type) -> Results<T>? {
invokedGetObjects = true
invokedGetObjectsCount += 1
invokedGetObjectsParameters = (objects, ())
invokedGetObjectsParametersList.append((objects, ()))
return stubbedGetObjectsResult
}
Where type 'T' is undeclared.
While I was trying to generate a mock for a swift protocol, I saw an issue that it was failing multiple times in a row. Restarting Xcode / swift mock generator util sometimes helps. I can't provide a test project to check it out because have no idea how to reproduce it, but I have some ideas why it might be the issue:
Please, let me know your thoughts...
Hey! Thanks for a great support of this extension! I wonder how difficult to migrate support for generating mock for multiple protocols from AppCode extension? In the readme, I assume it's called "Generates mock conforming to both classes and protocols."
I'm talking about this use case:
protocol SelectableType {
func select()
}
protocol ReadableType {
func read()
}
protocol TextFieldType: SelectableType, ReadableType {
func display()
}
class TextFieldMock: TextFieldType {
func select() {
..
}
func read() {
..
}
func display() {
..
}
}
It seems like the parser change in release v1-beta.11 does not catch inherited members from parent protocols. It should traverse the inherited members.
It would be cool if the user of the plugin could format the output from the plugin according to their wishes / standards in relation to naming in particular, i.e. the use of the term ...Spy
for captured parameters or to enable the exclusion of some of the generated properties, e.g. the boolean invoked.
This would potentially make it easier for people to switch from a previous mocking tool in order to maintain consistency in their codebase.
Hi! So, I do have a project written both in Objective C and Swift. But I would like to write tests only Swift either for those Objective-C modules. Could I use this plugin to generate mocks of Objective C classes and protocols and use them on a Swift unit test?
I've tried this in Xcode 12.4 and AppCode 2020.3.4. It appears extensions are not supported, so this is a feature request to add support for extensions.
Notice when I attempt to create FooSpy
, the extension to Foo
is ignored.
class Foo {
func faa(){ }
}
extension Foo {
func laa() { }
}
class FooSpy: Foo {
var invokedFaa = false
var invokedFaaCount = 0
override func faa() {
invokedFaa = true
invokedFaaCount += 1
}
}
After following this steps:
Download the latest release here
Copy the app to the Applications folder.
Open the app
Select the path to your project (Why do I have to do this?)
Open Xcode
I don't see any mock specific subtab in the editor tab.
Xcode Version 8.3.2 (8E2002)
Swift Toolchain: Swift 3.0.1
Given a protocol with an optional property like:
protocol MyProtocol {
var myProperty: String? { get }
}
The following non-optional stubbed value is generated:
var invokedMyPropertyGetter = false
var invokedMyPropertyGetterCount = 0
var stubbedMyProperty: String!
var myProperty: String? {
invokedMyPropertyGetter = true
invokedMyPropertyGetterCount += 1
return stubbedMyProperty
}
Would it be possible for optional properties to have optional stubbed values?
I would love to be able to install genmock
via Homebrew 😃
As per the title. I couldn't get the app to show in System Preferences until I renamed the application (I removed 'For Xcode' from the end).
Using OS X 10.13.6 and Mock Generator v1-beta.16.
Cheers
It used to work on Xcode 9.+ .
Once I have upgraded to Mojave and Xcode 10, the generator disappears from the editor menu.
Of course I have enabled permission at Check System Preferences -> Security & Privacy -> Privacy.
Also I have tried to reinstall and still not appearing in the menu.
Any suggestion how can it be solved? I really love this extension.
Edit: all of the extension not working for me. Is there anything I can do beside reinstall Xcode?
What's this -> ObjectToTest
where is ObjectToTest's implementation
Looks like a great tool.
I was hoping to use this tool 'out of the box', but the initial documentation is confusing about how to actually install it:
Install Swift Mock Generator Xcode Source Editor Extension:
Close Xcode if it is open: (check)
Download the latest release here (check)
Copy the app to the Applications folder. (What app?)
Open the app (What app?)
.. Gave up
I wonder if it was considered to use Apple Script (https://gist.github.com/schwa/3822611) to check what is the currently opened project folder instead of manually specifying it in the mock generator util.
Hey guys,
I just updated to the Big Sur beta 10 with Xcode 12.1. However, when I try to generate mocks, the option isn't available for me anymore in the editor menu.
Any idea why?
Thanks!
I'm experiencing an issue where my first mock works fine but after that there is a long period of time and then I get a message that the project could not be auto detected and to set the path manually. The only problem is it is already set manually. The first time it was on automatic so I changed it to manual earlier this morning. In order to fix this I have to click automatic and then back to manual and then it will generate successfully. I have closed the project and reopened but that did not resolve the issue.
Hi, I'd like to help in getting 3rd party framework inheritance support, if time allows, can you please describe in high level what's missing to support that?
When I copied the app to Applications folder and try to open it, it gives an error:
“MockGeneratorApp.app” is damaged and can’t be opened. You should move it to the Trash.
I have Mac OS X 10.12.6
Hello,
I am having issues setting up Swift Mock Generator for Xcode in System Preferences: when I go to System Preferences -> Extensions -> Xcode Source Editor, the app is not listed.
Because of this, when I go to Editor, there is no 'Mock Generator' entry.
However, if I go to Security & Privacy > Privacy > Automation, the app is listed and checked.
I have tried to reinstall the app, nothing changed.
Everything worked well until this new year, maybe there is something about capabilities / signing ?
Thank you!
macOS version: macOS Catalina (10.15.1)
Xcode versions: 11.3
Swift Mock Generator for Xcode version: v1-beta.24
Example:
protocol UIApplicationInterface: AnyObject {
func open(_ url: URL, options: [UIApplication.OpenExternalURLOptionsKey: Any], completionHandler completion: ((Bool) -> Void)?)
}
extension UIApplication: UIApplicationInterface { }
Returned generated code:
class TestApplication: UIApplicationInterface {
var invoked = false
var invokedCount = 0
func {
invoked = true
invokedCount += 1
}
}
Please let me know if there is anything else you'd need from me! :)
I have a protocol like:
protocol TestType {
func set(model: Any, for app: Any, onSuccess: (() -> Void)?, onFailure: ((Error) -> Void)?)
}
for which I try to generate a mock. As a result I get this code:
class Test: TestType {
var invokedSet = false
var invokedSetCount = 0
var invokedSetParameters: (model: Any, app: Any)?
var invokedSetParametersList = [(model: Any, app: Any)]()
var stubbedSetOnFailureResult: (Error, Void)?
func set(model: Any, for app: Any, onSuccess: (() -> Void)?, onFailure: ((Error) -> Void)?) {
invokedSet = true
invokedSetCount += 1
invokedSetParameters = (model, app)
invokedSetParametersList.append((model, app))
_ = onSuccess?()
if let result = stubbedSetOnFailureResult {
_ = onFailure?(result.0)
}
}
}
I'm thinking if it would make more sense not to call the onSuccess automatically?
I found that if I change the protocol like:
protocol TestType {
func set(model: Any, for app: Any, onSuccess: ((Void) -> Void)?, onFailure: ((Error) -> Void)?)
}
then I get a correct mock:
class Test: TestType {
var invokedSet = false
var invokedSetCount = 0
var invokedSetParameters: (model: Any, app: Any)?
var invokedSetParametersList = [(model: Any, app: Any)]()
var stubbedSetOnSuccessResult: (Void, Void)?
var stubbedSetOnFailureResult: (Error, Void)?
func set(model: Any, for app: Any, onSuccess: ((Void) -> Void)?, onFailure: ((Error) -> Void)?) {
invokedSet = true
invokedSetCount += 1
invokedSetParameters = (model, app)
invokedSetParametersList.append((model, app))
if let result = stubbedSetOnSuccessResult {
_ = onSuccess?(result.0)
}
if let result = stubbedSetOnFailureResult {
_ = onFailure?(result.0)
}
}
}
When generating a spy with a function which has a closure, there's always an extra Void
parameter
protocol SimpleExampleProtocol {
func someFunction(callback: (Bool) -> (String))
}
class SimpleExampleMock: SimpleExampleProtocol {
var invokedSomeFunction = false
var invokedSomeFunctionCount = 0
var stubbedSomeFunctionCallbackResult: (Bool, Void)? // <--- here
func someFunction(callback: (Bool) -> (String)) {
invokedSomeFunction = true
invokedSomeFunctionCount += 1
if let result = stubbedSomeFunctionCallbackResult {
_ = callback(result.0)
}
}
}
so when setting up spies, we have to use a tuple always with an extra ()
at the end:
spy.stubbedSomeFunctionCallbackResult = (Bool, ())
Is this intentional behaviour? Instinctively it felt like spy.stubbedSomeFunctionCallbackResult = true
would be better, but possibly this is a misunderstanding.
Thanks!
I would like to be able to create Stub / Spy of framework objects.
import Photos
class PHAssetMock: PHAsset {
}
Hi!
I just used the mock generator for the first time, and I noticed that the stubbed properties don't match the signature method.
For example, if a method has this signature func object(forKey defaultName: String) -> Any?
, the associated stubbed property is var stubbedObjectResult: Any!
.
I'd like to have instead of this var stubbedObjectResult: Any?
, but maybe there is a reason that I don't get to not be able to have correct stubbed object ?
Hi,
The current version is not compatible with Xcode 11.3 and Mojave. Can you please direct me to a version which supports this configuration.
When attempting to generate anything using the plugin for the first time I am receiving this First selection was not a text range error.
Looking through the code I can see that this is being thrown because XCSourceEditorCommandInvocation.buffer.selections[0]
isn't of type XCSourceTextRange
, but I don't really know where to go from here.
macOS Mojave 10.14.1
XCode 10.0 (10A255)
When trying to generate a mock on Xcode 10, I just get the error message "Could not find a protocol on ", even though the protocol has been defined.
Hi,
First of all thanks for the great tool!
In some of my code I heavily rely on PromiseKit. And while the stub completion results provide great support for working with closures etc. when working with Promises I've got some issues In ensuring all of my code is executed when making my asserts. The same applies to working with stuff that's called in UIView.animate
completion blocks. Currently I'm modifying the generated mocks by adding a XCTestExpectation
variable I can set that will be fulfilled when the function is called.
I think it would be great if this could be added to the default generation as it would mean I no longer have to manually modify the generated code.
My custom implementation currently looks something like this:
protocol MyProtocol {
func someFunctionThatsCalledInAnimationBlock()
}
final class MyMock: MyProtocol {
var invokedSomeFunctionThatsCalledInAnimationBlock = false
var invokedSomeFunctionThatsCalledInAnimationBlockCount = 0
var someFunctionThatsCalledInAnimationBlockExpectation: XCTestExpectation?
func someFunctionThatsCalledInAnimationBlock() {
invokedSomeFunctionThatsCalledInAnimationBlock = true
invokedSomeFunctionThatsCalledInAnimationBlockCount += 1
someFunctionThatsCalledInAnimationBlockExpectation?.fulfill()
}
}
I hope you would consider adding this.
Best regards,
Jimmy
I'm not sure if I'm alone here, but since updating my Mac to Big Sur and Xcode 12.4, I cannot get the latest version (v1-beta.27) to work. I have tried reinstalling it and have also checked all the extensions, privacy and permissions. It runs for a few seconds and then nothing happens.
Getting error that AST cannot be used as it was compiled for 5.3 while Xcode 12 is using 5.3.2
We are noticing some long load times on our end when generating spies.
For example:
public protocol LocationProviding {
/// Call back delegate to receive location update events
var delegate: LocationProviderDelegate? { get set }
/// The most current location of the user
var location: Location? { get }
var locationIsEnabled: Bool { get }
var shouldSendToSettings: Bool { get }
/// Start tracking a user's location
func start()
/// Stop tracking a user's location
func stop()
func getPlacemarks(for location: CLLocation, completion: @escaping ((Result<[Placemark], Error>) -> Void))
func authorizationStatus() -> CLAuthorizationStatus
func requestLocationPermissions()
func requestLocation()
}
We have a protocol (listed above), this took ~2 minutes to generate whereas before it was pretty instantaneous.
To be fair, LocationProviding
is from a different target in our project. I've tried changing out @testable import
and just plain ole import
of that module in the mock file and neither of those seemed to help. In fact, I think that I had to specifically change the project path to the absolute root path of the project, rather than where the the file actually is (which would encompass both the target LocationProvider
is in as well as the target the mock is in).
Any ideas?
Also...would really love to know if you have any reading material how to get involved with these types of improvements, could totally get some additional eyes on helping keep! :)
Create a protocol with a static method:
protocol TestProtcol {
static func staticMethod()
}
And start a mock:
class Mock: TestProtcol {
}
Then generate a spy.
The static method will not be generated. I have a class that I can swap out for my tests, so generating mock static methods would be very useful.
At
the wordcompanion
is misspelled as componion
Hey, @seanhenry!
I've realised that subscript is not supported:
protocol FeatureFlagsByKeyStoring: class {
subscript(key: String) -> Bool? { get set }
}
class MockSubscript: FeatureFlagsByKeyStoring {
}
is is a known issue or something you want to support in future?
Having multiple versions of Xcode on my Mac, I have them named different ways (Xcode_9_4_1.app, Xcode_10.app, ...). When I open the app to install it in that configuration (with no app called Xcode.app), as soon as I select setup popup, a "Choose Application" popup appears in loop, the app being unresponsive, and me being unable to install it. I tested it on the last two releases with the same result.
When I rename one of my Xcode apps back to Xcode.app, then it works normally - the "Choose Application" popup doesn't appear as Xcode.app is automatically detected, without me having the possibility to select a different Xcode application, by the way.
This bug prevents users to install SwiftMockGeneratorForXcode on multiple version of Xcode, to install it on renamed versions of Xcode, and simply to choose on which Xcode application to install it - all of which should definitely be possible to do.
Thanks in advance for looking into it whenever you have the time, I'll work around that in the meantime by renaming my Xcode applications as needed.
Note: changing the name to Xcode.app, installing SwiftMockGeneratorForXcode then renaming it to Xcode_xxx.app doesn't solve the problem, trying to generate a mock then would trigger an error - Couldn't communicate with a helper application
.
I'm trying to generate a Spy class in my test target. When I go to Editor > Mock Generator > Generate spy, I get a "Could not find a protocol on..." error. This actually happens if I try to generate the Spy anywhere outside of the file containing the protocol itself. As a result, my workflow involves switching to the file containing the protocol, generating the Spy class and then cut / pasting it to my test target.
For what it's worth, I've tried the extension on a newly created project and it works fine in any file or target. Is there any way I can get you more detailing debugging information?
Using Xcode 10 and Mock Generator v1-beta.16.
Cheers
Hello!
I'm trying to build a project but it requires SwiftToolkit
and it's trying to clone it from git clone [email protected]:seanhenry/swift-toolkit.git
but failing with Please make sure you have the correct access rights and the repository exists.
Hello!!
I was using this library without problems until today, but after upload to Big Sur (v.11.0.1) now I can't find the "Mock Generator" option inside "Editor" menu. I tried to give again permissions using the Application but seems that doesn't works.
My Xcode version is 12.2.
Does anybody knows how to solve this issue?
Thank you!
I have a protocol with this function declaration:
protocol MyProtocol {
func add(observer: @escaping (SomeCustomType?) -> Void) -> Bool
}
The generated code looks like this:
var invokedAdd = false
var invokedAddCount = 0
var stubbedAddObserverResult: (SomeCustomType?, Void)?
var stubbedAddResult: Bool!
func add(observer: @escaping (SomeCustomType?) -> Void) -> Bool {
invokedAdd = true
invokedAddCount += 1
if let result = stubbedAddObserverResult {
observer(result.0)
}
return stubbedAddResult
}
So there is no way to get observer parameter in the test suite after this method has been called.
I have a few ideas on what to work on next but would like to get some input as to what you, the users of this app, would like. Please comment if you have a feature that you would like to see next.
Feature | Effort |
---|---|
Custom mock templates | L |
Class support | M |
Resolve items from 3rd party/system frameworks | XL |
This would rely on creating a custom resolve library since I don't think SourceKit is up for the challenge.
Hi guys, awesome work!
Do you know how can I run the mock generator from terminal? I'd like to automate some process and the tool is perfect to do my mocks.
Thanks in advance!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.