0

I am using OCMock 3 to write my unite tests in iOS project.

I have a foo method under School class:

@implementation School
-(NSString *)foo:
{
    // I need to mock this MyService instance in my test
    MyService *service = [[MyService alloc] init];

    // I need to stub the function return for [service getStudent]
    Student *student = [service getStudent];
    if (student.age == 12) {
       //log the age is 12
    } else {
      //log the age is not 12
    }
    ...
}

The Student looks like this:

@interface Student : NSObject
@property NSInteger age;
...
@end

In my test case, I want to stub the method call [service getStudent] to return a Student instance with age value 12 I defined:

// use mocked service
id mockService = OCMClassMock([MyService class]);
OCMStub([[mockService alloc] init]).andReturn(mockService);

// create a student instance (with age=12) which I want to return by function '-(Student*) getStudent:'
Student *myStudent = [[Student alloc] init];
myStudent.age = 12;

// stub function to return 'myStudent'
OCMStub([mockService getStudent]).andReturn(myStudent);

// execute foo method
id schoolToTest = [OCMockObject partialMockForObject:[[School alloc] init]];
[schoolToTest foo];

When I run my test case, however, the student returned by -(Student*)getStudent: method is not with age 12, why?

===== UPDATE ====

I noticed in internet, somebody suggested to separate the alloc and init to stub. I also tried it but it doesn't work as it says:

// use mocked service
id mockService = OCMClassMock([MyService class]);
OCMStub([mockService alloc]).andReturn(mockService);
OCMStub([mockService init]).andReturn(mockService);
// stub function to return 'myStudent'
OCMStub([mockService getStudent]).andReturn(myStudent);

When I do this & run my test case, the real implementation of -(Student*)getStudent: method get called... I can't understand why people says it works.

Leem.fin
  • 40,781
  • 83
  • 202
  • 354
  • 1
    As indicated in [this answer](http://stackoverflow.com/a/18512663/765298) you need to separately mock `alloc` and `init` methods for this to work. I'd strongly suggest you'd redesign your code, so that the `School` object would take your `MyService` as parameter - this makes it easier to test and maintain. I'm also flagging your question as duplicate. – Losiowaty May 30 '16 at 14:13
  • @Losiowaty, I tried separately mock `alloc` and `init`, it ends up running the real implementation. – Leem.fin May 30 '16 at 14:20
  • @Losiowaty, See my update please. And I really want to know why people say it works but not working for me. – Leem.fin May 30 '16 at 14:27
  • @Losiowaty, For me, the answer in the link you provided is not working with OCMock version 3. So, my question is not duplicated with anything. – Leem.fin May 30 '16 at 14:35
  • One thing that comes to mind - does `MyService` actually override `init`? – Losiowaty May 30 '16 at 14:41
  • Can you provide the entire test case from your update that isolates the problem to the MyService mock? – Kyle Parent Jun 02 '16 at 00:58
  • The problem here is that `init` is already implemented by the mock object, so when you call `[[MyService alloc] init]` your `alloc` stub successfully returns the mock object, but `init` returns something unexpected that is defined by `OCMock`'s implementation. The best solution to this (apart from using dependency injection) is to write a custom `init` method for `MyService` and stub that instead. Then make sure to change your `School` implementation to call `[[MyService alloc] customInitMethod]`. – Kyle Parent Jun 02 '16 at 01:10

1 Answers1

0

You cannot mock the init method. This is stated in the documentation (Section 9.3), but maybe it's too hidden.

Erik Doernenburg
  • 2,933
  • 18
  • 21