1

So I need to test whether a NSNotification is posted. I tried the following code to spy on the argument.

[[NSNotificationCenter defaultCenter] stub:@selector(postNotification:)];

__block KWCaptureSpy *notificationSpy = [[NSNotificationCenter 
defaultCenter] captureArgument:@selector(postNotification:) atIndex:0];

[[theValue(notificationSpy.argument.name) should] equal:theValue(SOME_NOTIFICATION)];

but the problem with this is the since it's asynchronous the argument is not always captured before testing. I can't add shouldEventually for notificationSpy.argument.name either as it throws NSInternalConsistencyException for accessing the argument before capturing.

I also tried, [[SOME_NOTIFICATION should] bePosted]; and it failed as well.

Vig
  • 1,532
  • 1
  • 12
  • 28

2 Answers2

3

You can use expectFutureValue() if you expect the notification to be sent sometime in the future:

[[expectFutureValue(((NSNotification*)notificationSpy.argument).name) shouldEventually] equal:@"MyNotification"];

You also won't get the NSInternalConsistencyException exception, as Kiwi seems to work fine with spies not yet resolved, if wrapped inside a expectFutureValue.

Other alternatives would be to

  • stub the sendNotification: method and "manually" capture the sent notification:

    __block NSString *notifName = nil;
    [[NSNotificationCenter defaultCenter] stub:@selector(postNotification:) withBlock:^id(NSArray *params) {
        NSNotification *notification = params[0];
        notifName = notification.name;
        return nil;
    }];
    [[notifName shouldEventually] equal:@"TestNotification"];
    
  • write a custom matcher that registers to the notification center and assert on that matcher:

    [[[NSNotificationCenter defaultCenter] shouldEventually] sendNotification:@"MyNotification"]];
    

Personally, I'd go with the custom matcher approach, it's more elegant and more flexible.

Cristik
  • 30,989
  • 25
  • 91
  • 127
  • I still get NSInternalConsistencyException even when I use expectFutureValue like you have mentioned. – Vig May 19 '15 at 14:16
  • Also, just wondering how would you spy on multiple notifications? i.e say I have posted two different notifications notificationSpy.argument.name would just have the first right, how would I spy on the second? – Vig May 19 '15 at 14:29
  • Hmm... I tested the code before posting it and it worked for me. What SDK are you using? – Cristik May 19 '15 at 16:32
  • Not sure about the multiple notifications spying, perhaps this deserves another SO question :) – Cristik May 19 '15 at 16:32
  • I am using 'Kiwi', '~> 2.3' I also posted another question for multiple notifications. Thanks – Vig May 19 '15 at 17:14
  • @Vig: I updated my answer and added two more solutions, either of them should work for you. – Cristik May 21 '15 at 07:28
2

I may be missing some context because you haven't explained the code being tested. Are you posting a notification? Or are you trying to assert that the IOS Framework posts a notification for you? Regardless, here are the problems I see with your approach:

  1. You need to run the action that posts the notification AFTER spying on the postNotification selector and BEFORE you assert the value of the spied argument. From the code you posted, It is not clear that this is happening.

  2. This solution SHOULD work if indeed the postNotification method is being called. I actually do not think this is an asynchronous problem. I frequently spy on the postNotificationName:object:userInfo: on the defaultCenter with success and no special async handling code.

  3. For checking equality of strings in Kiwi, do not wrap them in theValue(). theValue() is used to check equality on scalar properties. your assertion should look like this:

    [[((NSNotification*)notificationSpy.argument).name should] equal:@"myNotificationName"];
    

If this doesn't help get you your solution, please provide more code of the methods you are testing and the test methods in their entirety, as well as any other useful information.

ganta
  • 366
  • 2
  • 9
  • Great thanks, I have followed the same and as mentioned I get NSInternalConsistencyException since the argument hasn't been spied yet. – Vig May 19 '15 at 14:29