1

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.

But... why?

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...

Mirek
  • 4,013
  • 2
  • 32
  • 47
  • 2
    Unit testing != integration testing, basically. I don't like to be dogmatic about this - it's usually worth faking out (not necessarily mocking) dependencies which are hard to set up or take a long time, e.g. databases, but in some other cases I view it as fine to use the real thing. Also note that depending on your IoC container, you may well want to use it to find all the dependencies, but have appropriate "test" configurations as opposed to "production" configurations. – Jon Skeet Jan 20 '15 at 18:57
  • class Person(IDatabase) uses IDatabase interface. The interface can be the real database or a fake database. In the IOC container you say which one to use. That way you can build your whole component against a fake database. But because its not a real database you could argue you test it as a complete Test Scenario. – Herman Van Der Blom Aug 14 '23 at 08:40

2 Answers2

3

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.

1

Instead, component B must be mocked. But... why?

Simply put, Unit Testing is for testing a unitary piece of feature. If the test fails, will it be because of component A or component B?

What the test is about?

Does component B pass its own battery of tests?

Testing component A along with a real instance of B will not answer these questions. On the contrary, it will rise up more questions than it can actually answer.

Instead of testing, what would happen in the real application, I'm now reasonlessly falsificating component B....to what end?

Actually, it is to isolate component A from component B so that any misbehave is only caused by component A. This it to reduce complexity around testing and to make it clear what you are doing, hence the "unit" in unit testing.

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...

Basically, you can do it this way. And this is not only what matters in unit testing. Instead, using dependency injection, one shall mock every reference types so that one isolates component A from any external influence, that is to make sure that component A behaves according to the expectations.

The day you want to test component A with a real instance of component B is actually not the day you are doing unit testing, but this is called integration testing, and those tests shall be written after you are sure that every component behaves in its unitary form.

Please see the answers of this question: Unit Testing or Functional Testing?

On a side note, it is not recommended to use DI containers in unit testing. It complexes the tests for no added value.

Community
  • 1
  • 1
Will Marcouiller
  • 23,773
  • 22
  • 96
  • 162
  • So, unit tests are writen by developer and integration tests are written by whome? – pixel Jan 25 '19 at 18:39
  • 1
    @pixel This is also the responsibility of each developers to make sure everything integrates in a harmless fashion to the other pieces of software out there. – Will Marcouiller Jan 27 '19 at 15:09