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

Checking that a method was called twice with different values #326

Open
JamieREvans opened this issue May 6, 2015 · 10 comments
Open

Checking that a method was called twice with different values #326

JamieREvans opened this issue May 6, 2015 · 10 comments

Comments

@JamieREvans
Copy link

I'm trying to verify that a method gets called twice with specific values, but I can't seem to verify both calls, just the first. I have verified that the method is called twice and that the values are correct, but I'm not sure how to write the cedar spec.

Here is what I have:

        it(@"should call sleep with time intervals of 0 and 5", ^{

            // subject is a spied on object
            subject should have_received(@selector(someMethod:)).with(0); // Passes
            subject should have_received(@selector(someMethod:)).with(5); // Fails
        }  

The error I'm getting is this:

Expected <MyObject> to have received message <someMethod:>, with arguments: <5> but received messages:
  someMethod:<0>
  someMethod:<5>

Also, it doesn't seem you can verify that a method was called a specific number of times without overriding the invocation and tracking the count.

@idoru
Copy link
Contributor

idoru commented May 6, 2015

There were some recent changes to be more strict with passed types. What happens if you cast the argument to with() to the exact numeric type being passed to the method?

Yes, there currently isn't a matcher for this, but it certainly would be a welcome addition. For now I have filed a feature request in Cedar's public tracker: https://www.pivotaltracker.com/story/show/94038932

Alternatively, you can perform the assertions more directly on the messages captured by any double object by accessing them via [(id<CedarDouble>)double sent_messages]

@JamieREvans
Copy link
Author

I was able to get the sent_messages and use that to verify that I was getting the correct values, but there really should be a better way to validate multiple messages and their parameters.

Thanks for the help.

@akitchen
Copy link
Contributor

akitchen commented May 7, 2015

I agree, this should be supported. I just tried to reproduce the issue you described, but wasn't able to do so. What is the declared type of the argument in your example?

Here are the specs I added in HaveReceivedSpec.mm in Cedar's own spec suite:

it(@"should pass for multiple invocations with different arguments", ^{
    [incrementer incrementByNumber:@666];
    expect(incrementer).to(have_received(method).with(expectedParameter));
    expect(incrementer).to(have_received(method).with(@666));
});

//...

it(@"should pass for multiple invocations with different arguments", ^{
    [incrementer incrementBy:666];
    expect(incrementer).to(have_received(method).with(expectedParameter));
    expect(incrementer).to(have_received(method).with(666));
});

@akitchen
Copy link
Contributor

akitchen commented May 7, 2015

Oh, I realized it right after posting. It appears to be an NSTimeInterval, which is typedef double

This probably boils down to a failure to match floating point numbers. The equality matcher has the same problem, which is the reason for be_close_to().within()

@akitchen
Copy link
Contributor

akitchen commented May 7, 2015

As to the other question, how about have_received(selector).withCount(5) ? I guess I haven't missed not having this, but it seems like it could be useful

@tooluser
Copy link

tooluser commented May 7, 2015

Would it be possible to extend the have_received function with an index, so that the .with() behavior worked as well?

I think we may have written (not gracefully) a wrapper of some kind to do this at one point.

On May 6, 2015, at 21:36, Andrew Kitchen [email protected] wrote:

As to the other question, how about have_received(selector).withCount(5) ? I guess I haven't missed not having this, but it seems like it could be useful


Reply to this email directly or view it on GitHub.

@JamieREvans
Copy link
Author

@akitchen Does your example check different values? If expectedValue is @666, the test would definitely pass. I'm talking specifically about having two different values - the same method called multiple times with different parameters.

@akitchen
Copy link
Contributor

akitchen commented May 7, 2015

They are different values. these code snippets were additions to cedar's own test suite.

On Thu, May 7, 2015 at 6:47 AM, Jamie Riley Evans
[email protected] wrote:

@akitchen Does your example check different values? If expectedValue is @666, the test would definitely pass. I'm talking specifically about having two different values - the same method called multiple times with different parameters.

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

@idoru
Copy link
Contributor

idoru commented May 8, 2015

Adding a method that takes an NSTimeInterval to SimpleIncrementer and this snippet in HaveReceivedSpec.mm reproduces the error:

    context(@"with a time interval", ^{
        fit(@"should get types right", ^{
            [incrementer incrementByTimeInterval:0];
            [incrementer incrementByTimeInterval:5];

            //fail
            incrementer should have_received(@selector(incrementByTimeInterval:)).with(0);
            incrementer should have_received(@selector(incrementByTimeInterval:)).with(5);
            //pass
            incrementer should have_received(@selector(incrementByTimeInterval:)).with((NSTimeInterval)0);
            incrementer should have_received(@selector(incrementByTimeInterval:)).with((NSTimeInterval)5);
            //also pass because NSTimeInterval is double
            incrementer should have_received(@selector(incrementByTimeInterval:)).with(0.0);
            incrementer should have_received(@selector(incrementByTimeInterval:)).with(5.0);
        });
    });

The literal 5 is implicitly an int. In cases like NSTimeInterval you can get away with adding a .0 to get an implicit double. Unfortunately for other types such as CGFloat which is double on the 64-bit iOS devices and float on 32-bit ones I've been forced to cast to CGFloat to keep specs passing on all devices. It's worth noting that for sanity I've found one should avoid float literals (unless for some reason you're only building for 32-bit) for CGGeometry expressions (CGRect et al) and then you're also more likely to get success with the equals matcher instead of relying so heavily on `be_close_to() for those truly equal cases.

@codeman9
Copy link
Contributor

I like the idea of having this have_received(selector).withCount(5) option.

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

5 participants