michal.ciurus
michal.ciurus

Reputation: 3664

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:];

?

Upvotes: 7

Views: 531

Answers (4)

Adam Borek
Adam Borek

Reputation: 26

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

Upvotes: 1

michal.ciurus
michal.ciurus

Reputation: 3664

The answer is: It's not better. It's only better if you need some super custom behavior.

The best thing about it is that you don't have to create an interface/protocol for every class you inject and you can limit to DI the modules you really need to inject making your code cleaner and more YAGNI.

It applies to any dynamic language, or language with reflection. Creating so much clutter just for the sake of Unit-Tests struck me as a bad idea.

Upvotes: 0

dogsgod
dogsgod

Reputation: 6387

With DI you inject your model at runtime, it's not bound in your classes but only in the configuration.
When you want to mock you just create a mock model and inject that instead of your real data. Besides the model, you changed your implementation in a single line.

See here for a hands on example or here for the idea behind it.

Disclaimer: Of course you can mock other stuff than the model, but that's probably the most common use-case.

Upvotes: 0

Loyal Tingley
Loyal Tingley

Reputation: 900

Imagine you are trying to test a more complex behavior of an object interacting with one of its child objects. To make certain that the parent object is operating correctly, you have to mock all the methods of the child object and even potentially track its changing state.

But if you do that, you just wrote an entirely new object in a confusing and convoluted way. It would have been simpler to write an entirely new object and tell the parent to use that.

Upvotes: 0

Related Questions