Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is mocking with DI better than mocking objects in objective-c?

this blog article says that:

While there are sometimes sensible ways to mock out objects without DI (typically by mocking out class methods, as seen in the OCMock example above), it’s often flat out not possible. Even when it is possible, the complexity of the test setup might outweigh the benefits. If you’re using dependency injection consistently, you’ll find writing tests using stubs and mocks will be much easier.

but it doesn't explain why. What are possible scenarios where DI (injecting an id object conforming to protocol) will serve better for mocking in Objective-C, than simple OCMockito:

[given([mockArray objectAtIndex:0]) willReturn:@"first"];
 [verifyCount(mockArray, times(1)) objectAtIndex:];

?

like image 525
michal.ciurus Avatar asked Apr 17 '15 13:04

michal.ciurus


People also ask

What is the goal of using mock object or mocking?

Using mock objects allows developers to focus their tests on the behavior of the system under test without worrying about its dependencies. For example, testing a complex algorithm based on multiple objects being in particular states can be clearly expressed using mock objects in place of real objects.

What is the purpose of mocking a dependent object?

Mocking is a way to replace a dependency in a unit under test with a stand-in for that dependency. The stand-in allows the unit under test to be tested without invoking the real dependency.

What are two reasons for mock objects in unit tests scrum?

A mock object can be useful in place of a real object that: Runs slowly or inefficiently in practical situations. Occurs rarely and is difficult to produce artificially. Produces non-deterministic results.


1 Answers

I've noticed that it is easier to create a separate class for test target when the original class do some async stuff.

Let assume you write a test for UIViewController which has a LoginSystem dependency which uses AFNetworking to do a request to the API. LoginSystem takes a block argument as a callback. (UIViewController->LoginSystem->AFNetworking).

If you make a mock of LoginSystem probably you will end with problems how to fire a callback block to test your UIViewController behaviour on success/failure. When I tried that I ended with MKTArgumentCaptor to retrieve a block argument and then I had to invoke it inside a test file.

On the other hand, if you create a separate class for LoginSystem (let call it LoginSystemStub which extends from LoginSystem) you are able to "mock" a behaviour in 3 lines of code and outside the test file. We should also keep our test file clean and readable.

Another case is that verify() doesn't work with checking asynchronous behaviour. It is much more easier to call expect(smth2).will.equal(smth)

EDIT:

Pointers to NSError (NSError**) also don't work well with verify() and it's better to create a stub :D

like image 158
Adam Borek Avatar answered Sep 28 '22 07:09

Adam Borek