Can anyone explain me why when i declare variable like this:
private let viewModel = TermsAndConditionViewModel()
// TermsAndConditionViewModel
class TermsAndConditionViewModel {
private let permissionsModel: PermissionsModel
private let userSession: UserSessionManager
init(
permissionsModel: PermissionsModel = PermissionsModelImpl(),
userSession: UserSessionManager = UserSessionManager.shared
) {
self.permissionsModel = permissionsModel
self.userSession = userSession
}
}
and run test in Xcode I got warning like
update: there is no message about warning.
and this is when I check in Xcode/Coverage
Thank for your help.
Hi #user2629744 welcome to StackOverflow.
The red bar you are seeing in the right gutter is not a warning but Xcode's Code Coverage Annotation.
It's red and it shows a 0 because there is no test exercising that code path.
It's hard to be sure without having access to your codebase, but since we're talking about a view model in your example I'm guessing that line of code comes from the view layer. Right?
If that's the case, it might be okay if you don't test it. If all the business logic lives in the view model (which you can throughly test) and you keep your view layer humble, then you'll still have the majority of your behavior covered.
Related
This is a swift question.
I have a question on getting the placeholder (or id, etc.) from a line XCUIApplication().someView.searchField.element.
I need to achieve this in order to get the text attributes of the elements that are tap()-ed in a test code.
Below is the exact code, gotten from the https://github.com/BalestraPatrick/Tweetometer/blob/a11c20244a37eacd4a36586f679f3ba184c66f86/Carthage/Checkouts/IGListKit/Examples/Examples-iOS/IGListKitExamples-UITests/SearchViewControllerUITests.swift.
import XCTest
final class SearchViewControllerUITests: UITestCase {
var collectionViews: XCUIElementQuery!
...
func test_whenSearchingForText_thatResultsGetFiltered() {
let searchField = collectionViews.searchFields.element <- ex) this element's placeholder.
searchField.tap()
searchField.typeText("tac")
let tacos = collectionViews.cells.staticTexts["tacos"]
let small = collectionViews.cells.staticTexts["small"]
XCTAssertTrue(tacos.exists)
XCTAssertFalse(small.exists)
}
}
The full code is available in the above link, but I am very new to Swift, so that I have no idea where to find the view and the element's site of declaration (something like .xml in android code?)
Actually, I am curious if this is possible in a static way (i.e. only looking at the code, not really exploring through the GUI).
Thanks in advance for any kind of hint!
In a project I want to declare a variable #GestureState, however I get the following error for no reason: "enum 'GestureState' cannot be used as an attribute".
I've worked with this kind of wrapper property before and didn't get this error at the time.
If anyone has an idea where this error might come from, I'll take it.
#GestureState var selected = false // error here :/
This happening because somewhere in the project you're creating an enum named GestureState rename it to something else and you're good to go.
Modify this:
enum GestureState { ... }
To this:
enum GestureStateType { ... }
I'm using Xcode 8 and Swift 2.3 and trying to debug a Core Data problem I'm having with inserting some default data into the persistent store. I'm learning from a Core Data book and in a little above my head
This function is checking to see if we even need to import the default data (trust me, we do) and then will set it up if necessary:
func checkIfDefaultDataNeedsSetup (url:NSURL, type:String) {
if isDefaultDataAlreadySetupForStoreWithURL(url, type: type) == false {
if let lift = NSEntityDescription.entityForName("Lift", inManagedObjectContext: CDHelper.shared.context) { /*breakpoint*/ 1
// not returning here
let newLiftEvent = Lift(entity: lift, insertIntoManagedObjectContext: CDHelper.shared.context)
newLiftEvent.uid = 0
newLiftEvent.liftName = "Back Squat"
CDHelper.saveSharedContext()
} else {
// skip setup
}
return
}
At breakpoint1 it calls CDHelper.shared.context (the inManagedObjectContext argument) where I have it stopping at breakpoints 2 and 3:
private let _sharedCDHelper = CDHelper() /* breakpoint 3 */
class CDHelper : NSObject {
// MARK: - SHARED INSTANCE
class var shared : CDHelper {
return _sharedCDHelper /* breakpoint 2 */
}
When stopped at breakpoint 3, as soon as I click Step Into I get this:
I would expect it to return to the next line after breakpoint 1 where it went off to get CDHelper.shared.context but it doesn't. Xcode and Simulator aren't hung up or anything. It just gets to this point and stays there as if its waiting for something.
I'm guessing this optional binding if let lift = NSEntityDescription.entityForName("Lift", inManagedObjectContext: CDHelper.shared.context) isn't getting assigned so it's not going into the method. But I'm as certain as I can be that the Lift entity is in the managedObjectContext. I see it in my .xcdatamodeld, I've looked in the db using DB for SQLite, and I've even deleted the data model and recreated it. I've also ensured that I'm using just the .MainQueueConcurrencyType.
Is there an obvious problem that anyone can see or are there other things I should look for? Maybe something else I can do to ensure the Lift entity is in the managed object context like I think it is?
I'm guessing this optional binding if let lift = NSEntityDescription.entityForName("Lift", inManagedObjectContext: CDHelper.shared.context) isn't getting assigned
Why guess? Remove or disable all breakpoints and put a breakpoint on that line. Now run the app. When we pause at that breakpoint, step over. Now look to see where you are.
Xcode 8 and Swift 3 made me really sad today :(
Please have a look and tell me if you ever had something like this and if it's possible to fix it. I've been trying different solutions, among them:
Cmd + Shift + K
Cmd + Shift + Option + K
Delete Derived Data
Change used struct (it's a nested struct in my code), flattened it, change to really basic one
Update 1:
Here's the code (although I think it's not necessarily a problem related to my implementation), it's in my tests target:
let viewModelStub: Quiz.NewRoundDetails.ViewModel = Quiz.NewRoundDetails.ViewModel(roundNumber: "", score: "", proposedAnswerParts: [
Quiz.NewRoundDetails.ViewModel.AnswersForComponent(answers: []),
Quiz.NewRoundDetails.ViewModel.AnswersForComponent(answers: []),
Quiz.NewRoundDetails.ViewModel.AnswersForComponent(answers: [])])
_ = viewController.view
viewController.display(roundModel: viewModelStub)
Here are structs:
struct Quiz {
struct NewRoundDetails {
struct Response {
let roundNumber: Int
let score: Int
}
struct ViewModel {
let roundNumber: String
let score: String
let proposedAnswerParts: [Quiz.NewRoundDetails.ViewModel.AnswersForComponent]
struct AnswersForComponent {
let answers: [String]
}
}
}
}
And in viewController things look like this:
func display(roundModel: Quiz.NewRoundDetails.ViewModel) {
...
}
Nothing so unusual I think. I have just discovered one more thing - the code works fine on the app target side, it doesn't work on tests target.
I don't have more ideas atm... Can you help me? I have created radar as well
Check this answer: Stack Overflow
It's probably an issue with targeting. If you're using the #testable key word on the top of your test file and your main project files also target your tests then the tests are referring to two different files. So your files should only target either the tests (if they're a test file) or the main project. If they have both checked uncheck one and use the #testable import [your project's name] at the top of your test file.
Ok, I got it...
I've imported my app's module with #testable and also I've had added my .swift file with model classes to the test target. Probably <MyTestModule>. Quiz.NewRoundDetails.ViewModel have been created instead of <MyAppModule>. Quiz.NewRoundDetails.ViewModel
I've been reading up on ReactiveCocoa v3 lately and I'm struggling with just setting up basic stuff. I've already read the changelog, the tests, the few SO questions and the articles by Colin Eberhardt on the subject. However, I'm still missing examples on basic bindings.
Let's say I have an app that presents the menu of the day. The app is using RAC3 and the MVVM pattern.
Model (Menu)
The model has one simple method for fetching todays menu. As for now, this don't do any network requests, it basically just creates a model object. The mainCourse property is a String.
class func fetchTodaysMenu() -> SignalProducer<Menu, NoError> {
return SignalProducer {
sink, dispoable in
let newMenu = Menu()
newMenu.mainCourse = "Some meat"
sendNext(sink, newMenu)
sendCompleted(sink)
}
}
ViewModel (MenuViewModel)
The view model exposes different String variables for letting the view controller show the menu. Let's just add one property for showing the main course.
var mainCourse = MutableProperty("")
And we add a binding for this property:
self.mainCourse <~ Menu.fetchTodaysMenu()
|> map { menu in
return menu.mainCourse!
}
ViewController (MenuViewController)
Last but not least, I want to present this main course in a view. I'll add a UILabel for this.
var headline = UILabel()
And finally I want to set the text property of that UILabel by observing my view model. Something like:
self.headline.text <~ viewModel.headline.producer
Which unfortunately does not work.
Questions
The method fetchTodaysMenu() returns a SignalProducer<Menu, NoError>, but what if I want this method to return a SignalProducer<Menu, NSError> instead? This would make my binding in my view model fail as the method now may return an error. How do I handle this?
As mentioned, the current binding in my view controller does not work. I've been playing around with creating a MutableProperty that represents the text property of the UILabel, but I never got it right. I also think it feels clumsy or verbose to have to create extra variables for each property I want to bind. This was not needed in RAC2. I intentionally also tried to avoid using DynamicProperty, but maybe I shouldn't? I basically just want to find the right way of doing RAC(self.headline, text) = RACObserve(self.viewModel, mainCourse);.
Any other feedback/guidance on how to make this basic setup is highly appreciated.
So, after writing this question Colin Eberhardt made a part 3 of his RAC3 blog post series which includes a interesting and very relevant example of using MVVM and RAC3. The post can be found here and the source code here.
Based on his work, I've managed to answer my own questions:
By taking a slightly different approach, I'm able to make the fetchTodaysMenu() return a SignalProducer<Menu, NSError> as wanted. Here's how what I then would do in my view model:
MenuService.fetchTodaysMenu()
|> observeOn(QueueScheduler.mainQueueScheduler)
|> start(next: { response in
self.mainCourse.put(response.mainCourse!)
}, error: {
println("Error \($0)")
})
It seems like there's no UIKit bindings yet as of RAC3 beta 4. Colin made some UIKit extensions himself to help him make these bindings I was looking for as well. These can be found here. Adding them to my project, made be able to do exactly what I wanted to:
self.mainCourse.rac_text <~ self.viewModel.mainCourse
Update May 25, 2015
After been working a lot more with ReactiveCocoa 3, I would like to answer 1) once again. By using catch, it's possible to do this in a more declarative manner. I ended up implementing a small helper function for this:
public func ignoreError<T: Any, E: ErrorType>(signalProducer: SignalProducer<T, E>) -> SignalProducer<T, NoError> {
return signalProducer
|> catch { _ in
SignalProducer<T, NoError>.empty
}
}
The function transforms any NSError to NoError making it possible to bind as I wanted to by doing MenuService.fetchTodaysMenu() |> ignoreError.
I open sourced my project as this might be a good starting point for others looking into ReactiveCocoa 3.0:
https://github.com/s0mmer/TodaysReactiveMenu
Update March 5, 2016
As highlighted in the comments, since Swift 2, the ignoreError function would now look like:
public func ignoreError() -> SignalProducer<Value, NoError> {
return flatMapError { _ in
SignalProducer<Value, NoError>.empty
}
}
Also, an extension library called Rex has also been made, where something similar has been added.