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

You can't call a method on the runtime argument being passed in. It has to be passed in as-is #233

Closed
ronak2121 opened this issue Jun 6, 2014 · 31 comments

Comments

@ronak2121
Copy link

I'm in the process of upgrading from Typhoon 1.8.6 to 2.0.7 and writing my Assemblies, but I'm greeted by this error whenever I launch.

I have about 20 view controllers in my application. These view controllers extend a base view controller we have that declares a bunch of dependencies.

Naturally, I am looking to share the code to set these dependencies as well.
I tried making a private shared method which sets these but it results in the above exception at run time.

Is the preferred way to have a definition defined in the assembly for the base class itself?

Thanks

Ronak

@jasperblues
Copy link
Member

You can do so following this process.

I'm sorry, but until just now this was missing from the docs.

Let us know when you're all good, so we can close the issue.

Or, if you still have problems and you'd like to share your assembly config, you can:

(or post it here if you like)

@ronak2121
Copy link
Author

Thanks a lot. I am also wondering how I can unit test my assembly files? Is there any way to inject mocks?

Sent from Yahoo Mail for iPhone

@ronak2121
Copy link
Author

There are also a ton of Selector not found warnings. Seems like I have to do extra casting just to get those warnings away (I can also just use the #pragmas but that doesn't seem like the best solution here). What's the best way to do this and your recommended way when using Typhoon Assemblies?

@jasperblues
Copy link
Member

Selectors:

Typhoon tests necessarily have these warnings (testing invalid names etc). Under normal use you shouldn't see such warnings. Something is wrong.

Testing:

Well there are two approaches to testing at the API level.

Unit Testing: Testing a class in isolation from its collaborators using mocks are stubs.
Integration testing: Testing a class including with its collaborators.

Unit Test Disadvantages:

  • Encourage glass-box testing as opposed to black-box testing. (ie mocks make it necessary to know what's going on inside a class, in order to test the external interface.
  • Can be costly to set up or support changes.

Integration Test Advantages:

  • Bang-for-your-buck: A small investment can provide very high test coverage
  • Ensures components are working together as they were intended
  • Encourages black-box style testing. Its not necessary to know what's going on inside a class. Just what's necessary to exercise the external API.

Now recently there's been renewed discussion on when to use integration tests vs unit tests. Ruby's founder published an article called "TDD is dead", which despite the intentionally controversial title was more about unit testing vs integration testing.

He sees value following the natural progression of the application. So if you have a discrete unit of course its going to be a unit test. If you have a class that's all about joining collaborators together and orchestrating a process, then naturally favor integration testing.

Of course some integration tests can be difficult to set up: Getting the system into the required state, starting with a valid user, rolling back the results, etc. Fortunately the dependency injection pattern encapsulates configuration, so you can swap out one component for another. There's two main ways to do this with Typhoon:

  • TyphoonPatcher
  • Overriding a definition.

Summary:

  • To use the unit-style of testing, your class should already be communicating its dependencies. Simply inject mocks or stubs.
  • Because an assembly is all about building an application from its constituent parts, then it naturally follows that an integration tests should be used to test the assembly itself. When you resolve a component from the assembly, you will have achieved test coverage for that assembly method. (Shown with a test coverage tool).
  • Typhoon allows you to configure integration tests, by swapping one or two components for another, in order to support that test scenario.

There's another DI container or two that allows you to inject all mocks in place of real collaborators. We like to have you provide the mocks because the expectations for each test scenario will be different. (A problem with stubs is that if you try to write one that supports all test scenarios, then they can become brittle).

Mocks vs stubs described here: http://martinfowler.com/articles/mocksArentStubs.html

@ronak2121
Copy link
Author

Regarding the selector issue, do you have any suggestions on things I can look at fixing?

Here's an example of my assembly file that exhibits this issue:

  • (RODiscoverManager *)discoverManager {
    ROTyphoonManagerAssembly *__weak weakSelf = self;

    return (RODiscoverManager *)[TyphoonDefinition withClass:[RODiscoverManager class] configuration:^(TyphoonDefinition *definition) {
    [definition useInitializer:@selector(initWithCredentialsManager:retrieverFactory:) parameters:^(TyphoonMethod *method) {
    [method injectParameterWith:[weakSelf credentialsManager]];
    [method injectParameterWith:[weakSelf retrieverFactory]];
    }];

    [definition setScope:TyphoonScopeSingleton];
    

    }];
    }

@jasperblues
Copy link
Member

As long as the class containing the selector is in the target's compile phase, it will be registered. Is it?

@ronak2121
Copy link
Author

Yes it is. Everything compiles and runs fine at runtime. I only get these warnings at compile time.

@jasperblues
Copy link
Member

Odd. And all imported?

You can work around this using:

sel_registerName("initWithFoo:bar:baz:");

. . . but more importantly should find out why this is happening.

@alexgarbarev
Copy link
Contributor

Selector warning appears only on unknown selectors - you have to import heards which declare selector you use

@alexgarbarev
Copy link
Contributor

Also can use assembly interface without __weak cast for 'self'. it is unnecessary. There is no retain cycle on self

@ronak2121
Copy link
Author

All of the imports are there...but doesn't seem to make any difference. Cmd+Click takes me to the right selector...

@alexgarbarev
Copy link
Contributor

@ronak2121 could you share example project with these warning. I want to check why it happens..

@ronak2121
Copy link
Author

Sure. The main thing I'm doing are forward declarations in my Assembly.h and #imports in the .m. I'm not sure if that matters at all.

@jasperblues
Copy link
Member

Using forward declarations wherever possible in header files is encouraged. It won't cause the issue you've described.

If you would like to share your assembly you can post it here, or email it privately to [email protected]

@ronak2121
Copy link
Author

Hi Jasper,

I emailed you my assembly files the other day like you asked. Please let me know what you suggest to fix the warnings.

Thanks

On Wednesday, June 11, 2014 11:13 AM, Jasper Blues [email protected] wrote:

Using forward declarations wherever possible in header files is encouraged. It won't cause the issue you've described.
If you would like to share your assembly you can post it here, or email it privately to [email protected]

Reply to this email directly or view it on GitHub.

@jasperblues
Copy link
Member

What was the date + email subject? I don't think we received anything.

@ronak2121
Copy link
Author

I sent it on Wednesday the 11th. Subject is "assembly files for lots of selector warnings"

Sent from Yahoo Mail for iPhone

@ronak2121
Copy link
Author

I resent the email to you guys again over the weekend with the same subject. Hopefully you received it?

@jasperblues
Copy link
Member

Received, thanks. Will get back to you ASAP.

@ronak2121
Copy link
Author

Hi Jasper,

I know you are pretty busy; but was wondering if you had a chance to look at my assembly?

Thanks.

@ronak2121
Copy link
Author

Ping?

@alexgarbarev
Copy link
Contributor

I saw you email today, it is set of assembly files. All looks correct (except *__weak weakSelf = self; - weakify self is unnecessary, since block is not retained).
I cannot reproduce your situation from these files. (haven't project file and other files)
Try to create new test project, with assembly and test components then try to reproduce these warnings - if you'll reproduce - share with us to debug

@alexgarbarev
Copy link
Contributor

@ronak2121 ping?

@ronak2121
Copy link
Author

I'll try to fit making a test project into my schedule. I have other competing things going on.
For now; I'm going to ignore the warnings and come back to this.

On Thursday, June 26, 2014 2:29 AM, Aleksey Garbarev [email protected] wrote:

@ronak2121 ping?

Reply to this email directly or view it on GitHub.

@alexgarbarev
Copy link
Contributor

Ok, thanks. Will wait for example project

@jasperblues
Copy link
Member

Reproduced: In an Assembly you should use #import instead of forward declarations.

@ronak2121
Copy link
Author

Ahhhhh okay I will fix that thank you!

On Friday, June 27, 2014 6:40 AM, Jasper Blues [email protected] wrote:

Reproduced: In an Assembly you should use #import instead of forward declarations.

Reply to this email directly or view it on GitHub.

@ronak2121
Copy link
Author

So I removed all of my forward declarations in favor of #import; however these warnings are still there. Do I need to #import in the .h and the .m?

@alexgarbarev
Copy link
Contributor

I thought assembly files has imports in .m files - so all was ok.. Still waiting for example project, because project includes compiler settings(warning settings) and its easy to reproduce

@jasperblues
Copy link
Member

Normally you should use forward declarations in headers, and imports in .m files, except for the following:

  • Extending a class.
  • Conforming to a protocol (though you can use @protocol here)
  • Overriding a property with a more specific type.

Recently, I ran into another situation where I had to #import a class in a TypyhoonAssembly header (first time). I guess it had to do with the compile order. . . I just did it for the one effected file.

Otherwise, I'd get the unrecognized selector error.

Alternative: sel_registerName("initWithFoo:bar:baz:"); //Tell the compiler about the selector it hasn't encountered yet.

@ronak2121
Copy link
Author

Closing.

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

No branches or pull requests

3 participants