问题
Here is the tested code:
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *mailComposeController = [[MFMailComposeViewController alloc] init];
[mailComposeController setSubject:nil];
[mailComposeController setToRecipients:@[Text_Email_Me_Email]];
[mailComposeController setMailComposeDelegate:self];
[self.frontViewController presentViewController:mailComposeController
animated:YES
completion:nil];
}
Here is the testing code:
id mailComposerMock = [OCMockObject mockForClass:[MFMailComposeViewController class]];
[[[mailComposerMock stub] andReturnValue:@YES] canSendMail];
[[[mailComposerMock stub] andReturn:mailComposerMock] alloc];
(void)[[[mailComposerMock stub] andReturn:mailComposerMock] init];
[[[mailComposerMock expect] andReturn:nil] setMailComposeDelegate:self.contactItemManager];
[[[mailComposerMock expect] andReturn:nil] setToRecipients:@[@"email@email.com"]];
[[[mailComposerMock expect] andReturn:nil] setSubject:nil];
[[[mailComposerMock expect] andReturn:self.frontViewController] presentingViewController];
[self.contactItemManager handleSelectionOfContentItemWithTitle:Text_Contact_Me_Email_Me];
[mailComposerMock verify];
The error states:
[theTestingClass testEmailMe] failed: OCMockObject[MFMailComposeViewController]: unexpected method invoked: setSubject:nil
And as you can see, I am calling setSubject already.
回答1:
I haven't determined exactly why this is happening, but you can get around it if you build in some dependency injection:
- (void)handleSelectionOfContentItemWithTitle:(NSString *)title mailComposeViewController:(MFMailComposeViewController *)mailComposeViewController;
Additionally, avoid returning nil
in void methods.
[[mailComposerMock expect] setSubject:nil];
If you were to pass your mock object into a method that could take the compose controller as an argument, your test should work.
Alternatively you could mock a custom factory method:
+ (MFMailComposeViewController*)mailComposeViewController
{
return [[MFMailComposeViewController alloc] init];
}
Not quite an answer, but hopefully a helpful workaround. I avoid mocking alloc
and init
personally.
回答2:
I think that here:
(void)[[[mailComposerMock stub] andReturn:mailComposerMock] init];
should be passed mock from method partialMockForObject
not mockForClass
.
My proposition is that you should create second mock which is made by partialMockForObject
Finally:
id mailComposerMock = [OCMockObject mockForClass:[MFMailComposeViewController class]];
MFMailComposeViewController *mailComposer = [MFMailComposeViewController new];
id partialComposerMock = [OCMockObject partialMockForObject:mailComposer];
...
(void)[[[mailComposerMock stub] andReturn: partialComposerMock] init];
[[[partialComposerMock expect] andReturn:nil] setMailComposeDelegate:self.contactItemManager];
[[[partialComposerMock expect] andReturn:nil] setToRecipients:@[@"email@email.com"]];
[[[partialComposerMock expect] andReturn:nil] setSubject:nil];
[[[partialComposerMock expect] andReturn:self.frontViewController] presentingViewController];
...
[partialComposerMock verify];
来源:https://stackoverflow.com/questions/21968556/ocmock-unexpected-method-invoked-although-expected