12/08/2018, 13:04

Giới thiệu Framework OCMock

1. Giới thiệu Nếu search key word 'mock object' trên github bạn sẽ nhận được 1 list các thư viện, và khi chọn mục objective C bạn sẽ thấy thư viện OCMock đầu tiên với hơn 1000 sao. Trong bài viết này tôi sẽ giới thiệu với các bạn thư viện OCMock dùng để viết Mock cho iOS. 2. Yêu cầu Có ...

1. Giới thiệu

Nếu search key word 'mock object' trên github bạn sẽ nhận được 1 list các thư viện, và khi chọn mục objective C bạn sẽ thấy thư viện OCMock đầu tiên với hơn 1000 sao. Trong bài viết này tôi sẽ giới thiệu với các bạn thư viện OCMock dùng để viết Mock cho iOS.

2. Yêu cầu

  • Có kiến thức sơ lược về test double, test stub, test spy, Mocking Object Tham khảo tại:

    https://en.wikipedia.org/wiki/Test_double http://xunitpatterns.com/Test Double.html

3. Cài đặt

  • Download phiên bản mới nhất tại

    http://ocmock.org/download/

  • Giải nén được file libOCMock.a và thư mục chứa file header OCMock.

  • Tạo Thư mục như sau và copy vào folder project Screen Shot 2015-12-21 at 8.09.37 PM.png

  • Add library libOCMock.a

  • Config target Project Test như sau

    • Ở mục header search path add: '$$PROJECT_DIR)/usr/include'

    • Ở mục library search path add: '$$PROJECT_DIR)/usr/lib'

Screen Shot 2015-12-21 at 8.11.19 PM.png

4. Practice

Tình huống đặt ra là tôi có một list các persons hiển thị lên table view. Tôi có một phím add button khi nhấn vào phím thì add thêm một person vào datasource và reload lại tableview. Tôi muốn test là khi hàm add được gọi thì tableView được reload lại.

  • Hàm addPerson của controller:

     - (IBAction)addPerson:(id)sender {
    
     	Person *person = [Person new];
    
     	person.idNumber = (int)self.persons.count;
    
     	person.name = @"Test";
    
     	person.age = random()%20;
    
     	[self.personDAO addPerson:person];
    
     	self.persons = [self.personDAO loadPersons];
    
     	[self.tableView reloadData];
    
     }
    
  • Hàm Test của hàm add:

      - (void)testAdd{
    
      	//Stub
    
      	id plistMock = OCMClassMock([PListPersonDAO class]);
    
      	self.vc.personDAO = plistMock;
    
      	[self.vc addPerson:nil];
    
      	//Test Spy
    
      	OCMVerify([plistMock loadPersons]);
    
      }
    

Ở đoạn code trên tôi sử dụng OCMClassMock để tạo stub bạn có thể add thêm các behavior cho stub sử dụng các hàm dưới đây:

	- (id)andReturn:(id)anObject;
	- (id)andReturnValue:(NSValue *)aValue;
	- (id)andThrow:(NSException *)anException;
	- (id)andPost:(NSNotification *)aNotification;
	- (id)andCall:(SEL)selector onObject:(id)anObject;
	- (id)andDo:(void (^)(NSInvocation *invocation))block;
	- (id)andForwardToRealObject;

Và cuối cùng tôi sử dụng OCMVerify để verify rằng hàm loadPersons của pListDAO được gọi.

7. Các tính năng khác

  • Class mocks:

            id mock = [OCMockObject mockForClass:[SomeClass class]]
    
  • Expectations and verification:

    • Setup Verfiied Parameter

        [[mock expect] someMethod:someArgument]
      
    • Verify:

       [mock verify]
      
    • Delay verify:

        [mock verifyWithDelay:aDelay]
      
  • Stubs:

    • Add and return value:

       [[[mock stub] andReturn:aValue] someMethod:someArgument]
      
    • Add Method and throw exception:

        [[[mock stub] andThrow:anException] someMethod:someArgument]
      
    • Add Method with expected block:

       void (^theBlock)(NSInvocation *) = ^(NSInvocation *invocation) {};
       [[[mock stub] andDo:theBlock] someMethod:[OCMArg any]];
      
  • Class Methods:

     [[[mock stub] andReturn:aValue] someClassMethod]
    
  • Argument Constraint:

      [[mock expect] someMethod:[OCMArg any]]
      [[mock expect] someMethod:[OCMArg isNotNil]]
      [[mock expect] someMethod:[OCMArg isNotEqual:aValue]]
    
  • Protocol mocks: Create object conform to protocol

      id aMock = [OCMockObject mockForProtocol:@protocol(SomeProtocol)]
    
  • Observer mocks:

    • Create observer mock:

        id aMock = [OCMockObject observerMock]
      
    • Assgin notification observer to mock:

        [notificatonCenter addMockObserver:aMock name:SomeNotification object:nil]
      

6. Kết luận

  • So với thư viện Mockito của java thì thư viện OCMock còn thiếu nhiều Utility nhưng chúng rất có lợi cho việc test các hàm và behavior của app.
  • Tham khảo thêm tại: http://ocmock.org/reference/
  • Link Code: http://www.mediafire.com/download/7i9z5h9chv5jvps/OCMockTest.zip
0