Mocking vs IoC container in unit testing
TL;DR - I mixed up "Integration Tests" with "Unit Tests".
I'm confused about Unit Testing and IoC containers... :(
I've read this article about how you should not use IoC containers in Unit Testing. This seems to be an opinion of many people on SO and in various other articles. In Unit Tests, you test your methods but any dependencies should be mocked.
Using the aforementioned article, I'd like to ask some questions.
To put it another way, if component A calls component B then from a unit testing perspective, we cannot let component A call the actual implementation of component B. Instead, component B must be mocked.
We use a fake instead of the real component B so that 1) our tests do not rely on code in any other class, 2) component B returns the same data every time and 3) we can intercept calls to component B so we can check how and when it is being called.
ad. 1) Instead of testing, what would happen in the real application, I'm now reasonlessly falsificating component B....to what end? So that I know that component A is tested in isolated manner? But my application uses both components together and these components work together.
The citation implies that I have to Unit Test component A and component B in isolation and that I should test only the business of the component.
But that undermines the whole point of automated testing in which I create assurances about the functions of the application, that the application will not crash, using these two components together. Not about its internal units in isolated context.
ad. 2) I know that everything I test is deterministic and for various inputs X it will return some Y, or throw an exception or something else - that's what I'm actually testing.
ad. 3) I can imagine this makes sense in complex tests...
To me mocking makes sense if component B is a 3rd party code I cannot easily create in a testing class without duplicating an awful lot of a code...Or if I have reasons not to call the actual implementation of component B such as not really wanting to do actual changes in database, not actually sending emails, not actually moving/writing/reading/deleting files etc.
But then, I'd mock using a different IoC container, where instead of Bind<ISomeService>().To<BusinessImplementation>() I would write Bind<ISomeService>().To<TestImplementation() (code example in Ninject)
By testing, I want to make assurances about the application, what would happen in deployed application and by mocking dependencies without good reason, I test in a very different context.
When the application starts, it uses the IoC container as I wrote it. The dependencies of the application are resolved using the IoC container.
I believe I'm probably wrong about something but I can't see it yet...
The purpose isn't to replace integration tests that will test modules from a higher level. Unit tests are intended to test a discrete class in isolation, mostly to confirm that the design and coding of that class is complete.