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

Object instantiated as a different class on Spec #91

Closed
ravelantunes opened this issue Jul 7, 2014 · 16 comments
Closed

Object instantiated as a different class on Spec #91

ravelantunes opened this issue Jul 7, 2014 · 16 comments
Labels

Comments

@ravelantunes
Copy link

When initializing one of my controllers in a spec, I get the following class _TtC9OiOrlando14NewsController for an object that should be of type NewsController.

The following code works on a regular build, but crashes on the tests due to the incorrect typecasting:

    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let controller: NewsController = storyboard.instantiateViewControllerWithIdentifier("NewsController") as NewsController;

If I don't typecast to NewsController, but to UIViewController, it doesn't crash:

    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let controller: UIViewController = storyboard.instantiateViewControllerWithIdentifier("NewsController") as UIViewController;

This first test succeeds, and the second fails:

describe("the news controller after initialized") {
    it("is should be of type UIViewController") {
        expect(controller.isKindOfClass(UIViewController)).to.beTrue()
    }
}

describe("the news controller after initialized") {
   it("is should be of type NewsController") {
      expect(controller.isKindOfClass(NewsController)).to.beTrue()
    }
}

The NewsController class is correctly included in the Tests target.

Am I doing something wrong?
Are the objects being wrapped in a different object at runtime?

@modocache
Copy link
Member

Interesting! 💡

Are the objects being wrapped in a different object at runtime?

Wrapping an object is expect() doesn't modify the original object at all, so I don't think this is the case.

Am I doing something wrong?

Not that I can tell. Is it possible that instantiating the view controller using Swift instead of Objective-C returns an instance of a different class (one that uses a mangled Swift class name)?

In any case this definitely seems worth investigating. Thanks for the heads up, I'll keep you posted on what I find!

@ravelantunes
Copy link
Author

Thanks for the response.
The issue seems to be beyond the class name, as I'm not able to call any instance method.

I did one more test to make sure I'm setting the correct Storyboard ID and classes to the view controllers, etc, and it works when executed in my AppDelegate didFinishLaunching, but fails at the Spec.

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller: NewsController = storyboard.instantiateViewControllerWithIdentifier("NewsController") as NewsController;
controller.printSomething()
assert(controller.isKindOfClass(NewsController), "The controller should be of type NewsController")

However, directly initializing the controller works:

var controller = NewsController()
controller.printSomething()
assert(controller.isKindOfClass(NewsController), "The controller should be of type NewsController")

I don't believe it's a Quick issue at this point. It's probably some quirk way swift is dealing with storyboard on the test builds. Still worth investigating, as initializing controller from storyboards will be a necessity for many people. Would be good to have the issue validated by someone else also.

@dmeehan1968
Copy link
Contributor

Isn't that something to so with the tests bundle not being the same as the apps bundle? I was under the impression that you had to get a reference to the apps bundle, rather than passing nil?

Sort if that a rec herring, a long time since I did any UI tests in ObjC, let alone Swift!

On 7 Jul 2014, at 02:53, Ravel Antunes notifications@github.com wrote:

Thanks for the response.
The issue seems to be beyond the class name, as I'm not able to call any instance method.

I did one more test to make sure I'm setting the correct Storyboard ID and classes to the view controllers, etc, and it works when executed in my AppDelegate didFinishLaunching, but fails at the Spec.

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller: NewsController = storyboard.instantiateViewControllerWithIdentifier("NewsController") as NewsController;
controller.printSomething()
assert(controller.isKindOfClass(NewsController), "The controller should be of type NewsController")
However, directly initializing the controller works:

var controller = NewsController()
controller.printSomething()
assert(controller.isKindOfClass(NewsController), "The controller should be of type NewsController")
I don't believe it's a Quick issue at this point. It's probably some quirk way swift is dealing with storyboard on the test builds. Still worth investigating, as initializing controller from storyboards will be a necessity for many people. Would be good to have the issue validated by someone else also.


Reply to this email directly or view it on GitHub.

@ravelantunes
Copy link
Author

I believe as long as they are selected to be also part of the test target, they will be included in the test bundle. I have also trying the following without success:

var storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())

@jeffh
Copy link
Member

jeffh commented Jul 7, 2014

Is the view controller part of the test bundle? If so, try removing it from the target.

If you include it in both the app and test bundle, you'll have duplicate classes of the same name.

The app classes should be accessible without including them explicitly in the test bundle.

Sent from my iPhone

On Mon, Jul 7, 2014 at 4:59 AM, Ravel Antunes notifications@github.com
wrote:

I believe as long as they are selected to be also part of the test target, they will be included in the test bundle. I have also trying the following without success:

var storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())

Reply to this email directly or view it on GitHub:
#91 (comment)

@ravelantunes
Copy link
Author

If I don't add the class to the target it gives me a compile error, since it doesn't recognizes NewsController.

@ikesyo
Copy link
Member

ikesyo commented Jul 7, 2014

@ravelantunes You should import the application target module in the test class by import AppTargetName.

@ravelantunes
Copy link
Author

That was the issue, I was not importing my app target into the test target.

Might be worth noting that detail when extending examples to cover controller testing, as @modocache suggested in another issue. I might be able to contribute with that once I get a little more familiar with Quick and Swift.

Thanks for the help!

@modocache
Copy link
Member

Thanks for the diagnoses, everybody! 🍻 ✨

@akoi
Copy link

akoi commented Nov 18, 2014

@ravelantunes I'm having exactly the same issue while instantiating custom storyboard view controllers in a spec. I've tried the solution from @ikesyo, by adding an import for the application target, but without any success, so was hoping you could give a little more info on how you solved your problem?

@akoi
Copy link

akoi commented Nov 18, 2014

I've created a bare bones project here to reproduce the problem: SpecTest

@ravelantunes
Copy link
Author

I need to look through my project to see if I still have that, but I believe the issue was that I was marking the main target classes (controllers, views, etc) to also be available to the test targets, instead of importing the app target into the test targets.

@akoi
Copy link

akoi commented Nov 19, 2014

I've tried removing the controller from the tests target and using the import, but as you mentioned in your comments, I then get compile errors as the the view controller isn't recognised. I wonder if there's a configuration I'm missing for the import other than import {App-Target}...

Thanks for looking into it.

@akoi
Copy link

akoi commented Dec 3, 2014

I found a solution to the problem on the iOS Mike blog here. It's not related to Quick, but with instantiating storyboards in the test target.

By making the storyboard and view controllers have membership of both the main and test targets, and then using the following to instantiate the storyboard solved the casting issues for me:

let storyboard = UIStoryboard(name: "Main", bundle: NSBundle(forClass: self.dynamicType))

Finally I can start testing my view controllers with Quick - awesome!

@modocache
Copy link
Member

This is related to #212. I plan on adding instructions to the README on the best way to test UIStoryboard-based view controllers. I'm not sure adding the storyboard to the test target is the ideal solution, but I haven't looked into it a ton yet.

Thanks for all the continued feedback everyone! 👍

@modocache
Copy link
Member

Instructions added in #254. Thanks all!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants