Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ExpectThunk proposal #19

Merged
merged 24 commits into from
Jun 13, 2019
Merged

ExpectThunk proposal #19

merged 24 commits into from
Jun 13, 2019

Conversation

obj-p
Copy link
Contributor

@obj-p obj-p commented Feb 14, 2019

Hey all, this is just a thought that I've been exploring previously with ActionCreators and just open for discussion if it has a place somewhere in ReSwift. Here's and example of the previous rendition:
https://github.com/jjgp/ReddiX-iOS/blob/master/UNITests/Actions/ListingsActionsTests.swift

To make Thunks more testable especially when facing async things like mocking requests with MockingJay or OHHTTPStubs I created an ExpectThunk that is a subclass of XCTestExpectation.

If this is to be then there would have to be a subspec or other podspec for consumers to be able to pod install into their tests.

Cheer,

ReSwift-ThunkTests/Tests.swift Outdated Show resolved Hide resolved
ReSwift-ThunkTests/Tests.swift Outdated Show resolved Hide resolved
ReSwift-ThunkTests/Tests.swift Outdated Show resolved Hide resolved
ReSwift-ThunkTests/Tests.swift Outdated Show resolved Hide resolved
ReSwift-ThunkTests/Tests.swift Outdated Show resolved Hide resolved
ReSwift-ThunkTests/ExpectThunk.swift Outdated Show resolved Hide resolved
ReSwift-ThunkTests/ExpectThunk.swift Outdated Show resolved Hide resolved
ReSwift-ThunkTests/ExpectThunk.swift Outdated Show resolved Hide resolved
ReSwift-ThunkTests/ExpectThunk.swift Outdated Show resolved Hide resolved
ReSwift-ThunkTests/ExpectThunk.swift Outdated Show resolved Hide resolved
ReSwift-ThunkTests/Tests.swift Outdated Show resolved Hide resolved
@mjarvis
Copy link
Member

mjarvis commented Feb 14, 2019

Hey, this look great! I can see adding this as a sub-spec to making testing thunks easier.
One improvement I can see making is adding another dispatches function that takes a closure (Action) -> Void to be able to manually match and assert on actions outside of the Equatable restriction (maybe some action is difficult to make equatable).

ReSwift-ThunkTests/ExpectThunk.swift Outdated Show resolved Hide resolved
ReSwift-ThunkTests/ExpectThunk.swift Outdated Show resolved Hide resolved
@obj-p
Copy link
Contributor Author

obj-p commented Feb 14, 2019

@mjarvis great feedback! I will incorporate and leave this open a tad longer in case there is any other feedback. Then I will close and make some refactors and reopen the PR.

@mjarvis
Copy link
Member

mjarvis commented Feb 14, 2019

@jjgp you are welcome to leave the PR open and make changes in-place. We'll use a squash & merge to merge when its ready so any WIP commits will get squashed out.

@@ -0,0 +1,29 @@
Pod::Spec.new do |spec|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would probably be better suited as a subspec rather than a separate pod inside the same repo.
See https://guides.cocoapods.org/syntax/podspec.html#subspec and also https://guides.cocoapods.org/syntax/podspec.html#default_subspecs for omitting this from the default.

I would create two subspecs Core, and Expect, then set Core as the default_subspec

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm all for making it a subspec. I went with this route first to test it in a demo app. I will attempt a subspec next. Will report back on this.

Second thing I would be for adding a blurb in the README.md if that's cool.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe I got the subspec down. I have a test project here: https://github.com/jjgp/ExpectThunkDemo

I'd appreciate a sanity check since I did run into CocoaPods fun with a sigabrt at test time, however, I managed to resolve it.

Will work on the blurb in a bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sigabrt will show up if the test target is a child target in the Podfile:

target 'ExpectThunkDemo' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for ExpectThunkDemo
  pod 'ReSwiftThunk', :git => '[email protected]:jjgp/ReSwift-Thunk.git', :branch => 'expect-thunk-proposal'
  target 'ExpectThunkDemoTests' do
    inherit! :search_paths
    pod 'ReSwiftThunk/ExpectThunk', :git => '[email protected]:jjgp/ReSwift-Thunk.git', :branch => 'expect-thunk-proposal'
  end
end

@obj-p
Copy link
Contributor Author

obj-p commented Feb 21, 2019

travis is failing and I'll take a look in a bit

@xavierLowmiller
Copy link
Contributor

Are there any news on this?

I don't mean to be pushy, but we'd love to use this.

Or, since this is 'just' for tests, do you think it's viable to target this branch in our project?

@obj-p
Copy link
Contributor Author

obj-p commented Apr 17, 2019

Appreciate the interest! I’ll get back to it today. It should be near complete. After I double check I’ll ping for some reviews. Cheers,

end

spec.subspec "ExpectThunk" do |sp|
sp.dependency "ReSwiftThunk/Core"
Copy link
Member

@mjarvis mjarvis Apr 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you remove this dependency, perhaps the inherited podfile example will work? I think it might be double-importing Core when inherit is included in the test target pod specifications.

Edit: Though, really, cocoapods dependency stuff should really handle this automatically...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good thought, however, I wasn't able to get it to build this way. I'm attempting with CocoaPods 1.6.1. It may be an open issue with CocoaPods 7195 having child targets with subspecs. I'll follow up there, it does seem splitting the targets is the workaround in the Podfile at the moment.

@DivineDominion
Copy link
Contributor

DivineDominion commented Apr 18, 2019

I'm by no means a CocoaPods expert and almost never use it. Is it common to nest test targets inside the library/app target, or just an edge case?

Totally missed this whole PR -- looks very cool!

@obj-p
Copy link
Contributor Author

obj-p commented Apr 18, 2019

So CocoaPods defaults to nested targets on a pod init. That being said having them separate is common and often used as a workaround for certain issues. Even documentation such as RxSwift shows them as separate:

# Podfile
use_frameworks!

target 'YOUR_TARGET_NAME' do
    pod 'RxSwift',    '~> 4.0'
    pod 'RxCocoa',    '~> 4.0'
end

# RxTest and RxBlocking make the most sense in the context of unit/integration tests
target 'YOUR_TESTING_TARGET' do
    pod 'RxBlocking', '~> 4.0'
    pod 'RxTest',     '~> 4.0'
end

@DivineDominion
Copy link
Contributor

DivineDominion commented May 17, 2019

@jjgp Do you need any assistance to make things work? I'd very much like to integrate this rather sooner than later :)

Also, what do you think about exposing a record of dispatched actions or similar, so one can write e.g. 3 dispatches assertions and make sure only 3 actions have been dispatched in total (e.g. there's nothing on top of that).

@obj-p
Copy link
Contributor Author

obj-p commented May 18, 2019

Appreciate it @DivineDominion! I'm going to get a version of that dispatches in over the weekend. I had a few other thoughts as well.

The only thing I'm unsure about is CocoaPods. I tend to lean that breaking it into separate targets is acceptable for the end user. The issue sited on CocoaPods repo has been moved to a further milestone and perhaps I will have to contribute there.

I'll report back by the end of the weekend.

@obj-p
Copy link
Contributor Author

obj-p commented May 18, 2019

@DivineDominion currently I do not enforce the order of getStates within the dispatches/getStates chain. I haven't really thought about it, do you have an opinion of it?

@obj-p
Copy link
Contributor Author

obj-p commented May 18, 2019

Screen Shot 2019-05-18 at 2 37 33 PM

Work in progress, I have included the dispatches record as well as built in a way for ExpectThunk to mark parts of the chain that were not reached.

ReSwift-ThunkTests/Tests.swift Outdated Show resolved Hide resolved
ReSwift-ThunkTests/Tests.swift Outdated Show resolved Hide resolved
ReSwift-ThunkTests/Tests.swift Outdated Show resolved Hide resolved
ReSwift-ThunkTests/Tests.swift Outdated Show resolved Hide resolved
ReSwift-ThunkTests/ExpectThunk.swift Outdated Show resolved Hide resolved
@obj-p
Copy link
Contributor Author

obj-p commented May 18, 2019

Looks like the following Podfile works as well:

platform :ios, '12.1'

target 'ExpectThunkDemo' do
  pod 'ReSwiftThunk', :git => '[email protected]:jjgp/ReSwift-Thunk.git', :branch => 'expect-thunk-proposal'
  target 'ExpectThunkDemoTests' do
    pod 'ReSwiftThunk/ExpectThunk', :git => '[email protected]:jjgp/ReSwift-Thunk.git', :branch => 'expect-thunk-proposal'
  end
end

Moral of the story is that if your using the use_frameworks! option then it will SIGABRT in the tests probably because the framework isn't being dynamically linked or something like that.

Here is a branch where it works with the above Podfile sans use_frameworks!:
https://github.com/jjgp/ExpectThunkDemo/compare/separate-targets

Looking back at this comment, that is the distinction too: #19 (comment)

I'm leaning more towards this is fine CocoaPods wise as the user has a few options and the framework linking seems to make sense.

@obj-p
Copy link
Contributor Author

obj-p commented May 18, 2019

updated failure descriptions:
Screen Shot 2019-05-18 at 7 40 34 PM

@DivineDominion
Copy link
Contributor

Moral of the story is that if your using the use_frameworks! option then it will SIGABRT in the tests probably because the framework isn't being dynamically linked or something like that.

Do I read this correctly: this makes it impossible to use use_Frameworks! for devs who use this sub-spec of the pod?

@obj-p
Copy link
Contributor Author

obj-p commented May 20, 2019

use_frameworks!may still be used as long as the testing target is defined outside of the source target in the Podfile like in this demo project
https://github.com/jjgp/ExpectThunkDemo/blob/master/Podfile

It seems if the test target is nested in the source target and it declares use_frameworks! then the issue presents itself.

It could be related to this issue with CocoaPods as listed here: CocoaPods/CocoaPods#7195
Although I don’t see others using use_frameworks there. Actually: CocoaPods/CocoaPods#7195 (comment)

Another way I’ve seen test helpers implemented is as a separate CocoaPod entirely such as RxTest. I would have to test, however, I’m inclined to think it wouldn’t have the issue seen here.

@DivineDominion
Copy link
Contributor

Cool! I've tested the code in my app and really like the test helper. So if someone with more CocoaPods experience (maybe @mjarvis or @danielmartinprieto) accept the CocoaPods side of things, I think we should merge this 👍

@DivineDominion
Copy link
Contributor

@mjarvis @danielmartinprieto Does any one of you have an opinion regarding the pod subspec mentioned above?

@mjarvis
Copy link
Member

mjarvis commented Jun 5, 2019

I'm okay with a bit of awkwardness as long as:

  1. It doesn't affect installation of the main project
  2. Its well documented

@obj-p
Copy link
Contributor Author

obj-p commented Jun 5, 2019

I will update the README to make it more clear. Also looking to the future I’ll look into Swift Package Manager and it may make for a cleaner integration!

@obj-p
Copy link
Contributor Author

obj-p commented Jun 11, 2019

Just updated the README to make it explicit to not nest the targets if using the subspec 😄

@DivineDominion
Copy link
Contributor

Great 👍

Could you add your addition to the top of the changelog? (Sorry I'm serving all this info piecemeal and asking you to always edit one more thing :))

@obj-p
Copy link
Contributor Author

obj-p commented Jun 13, 2019

Just added a blurb to the changlog. I hope I put it in the expected place 😄

@DivineDominion
Copy link
Contributor

Just noticed you enabled editing by maintainers, that's good :) I edited in some details. Thanks for all this!

@DivineDominion DivineDominion merged commit f266ebf into ReSwift:master Jun 13, 2019
@obj-p obj-p deleted the expect-thunk-proposal branch June 21, 2019 01:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants