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

Support setting expectation or stubbing methods on toll-free bridged objects. #61

Closed
ma11hew28 opened this issue Sep 28, 2011 · 8 comments

Comments

@ma11hew28
Copy link
Contributor

This feature is a must for me.

@lukeredpath
Copy link
Contributor

As I mentioned in the previous issue, there is no obvious way of doing this. Any partial stubbing of real objects requires swapping out the method implementation at run-time which just isn't possible to do safely with toll-free bridged objects.

I'm not sure I really understand the use-case for this though; as a general rule of thumb, you should aim to only ever stub and mock types you own, which would preclude the need to stub native Foundation objects. Why do you need this?

@allending
Copy link
Member

Not feasible, if you were unlucky it might seem to work when you try.

Even stubbing and mocking Apple provided Objective-C types or types where you perform your own shenanigans with method implementations is a fragile exercise. The implementation that is there tries to be smart about it and should cover the basic cases, but simply cannot account for all the different scenarios where internal swizzling is taking place.

Like Luke, I'm curious as to when doing it would actually be desirable.

@lukeredpath
Copy link
Contributor

Matt: if you'd like to explain why you feel you need this, I'd be happy to try and help you find a better way.

@ma11hew28
Copy link
Contributor Author

Okay. Sorry for the late reply.

I would like to set expectations & stub methods on objects of class NSString, NSArray, etc. because:

Let's imagine I write a category on NSString to add the instance methods:

  1. -[NSString words], which returns an NSArray of the words in the receiver.
  2. -[NSString wordCount], which returns an NSUInteger of the number of words in the receiver.

To spec wordCount, I want to set an expectation that it should call words on a string and return some array. Then, I want to set an expectation on the returned array that it should receive count and return an NSUInteger wordCount. Then, I want to confirm that when I call wordCount, it returns the NSUInteger wordCount above.

Also, RSpec lets me set expectations and stub methods on String & Array.

@lukeredpath
Copy link
Contributor

I'm struggling to see why on earth you'd want to test like that. This isn't really the way to use mocks/stubs. Mocks are useful when you have objects playing clearly defined roles interacting with each other. They aren't so great for things like simple data transformation with no external dependencies like the above example.

It strikes me that a few simple input/output tests would be far more useful and less tightly coupled to your implementation.

I appreciate that RSpec let's you do these the with String and Array but that doesn't mean you should. "Only mock types you own" and "mock roles, not objects" are important rules to live by if you want to make good use of mocks.

@ma11hew28
Copy link
Contributor Author

I read, "unit tests should test a method's external behavior rather than its internal implementation," on Wikipedia Mock Objects.

And the RSPec Book says, "Even the most highly decoupled code has some dependencies. Sometimes they are on objects that are cheap and easy to construct and have no complex state. These generally don’t present a problem, so there is no need to create stubs for them."

So, if I used input/output tests to test wordCount, first, I guess I should make a factory or something because I'd be using the same input strings that I used to test the words method. That's cool I guess. But, second, if the words method has an error, the wordCount test would also fail even if it's implemented correctly.

I thought a unit test was only supposed to test one unit/method at a time?

P.S. I'm ordering that book you recommended off Amazon... :)

@ma11hew28
Copy link
Contributor Author

How should I stub NSDate methods like -timeIntervalSinceNow?

@yas375
Copy link
Contributor

yas375 commented Jan 7, 2013

I'm not sure should I open a new issue or better to ask here. So I will start with asking here)

I'm testing some network-related code and would like to stub statusCode method of NSHTTPURLResponse. But thit method should return NSInteger, but if I stub such method with NSNumber value it will return NSNumber too and next test will fail:

it(@"should return NSInteger from stubbed method", ^{
    NSHTTPURLResponse *mockedResponse = [NSHTTPURLResponse mock];
    [mockedResponse stub:@selector(statusCode) andReturn:@200];
    [[theValue(mockedResponse.statusCode) should] equal:theValue(200)];
});

Is there any way to stub method which are return for example NSInteger?

Thanks in advance.

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

4 participants