What is the difference between unit tests and integration tests? - lilbond/testable-code GitHub Wiki

As the name suggests, unit tests focus on a particular unit (class/function) and integration tests focus on overall system/feature.

e.g. Let us consider an MVC REST service and try to understand Integration tests via it:

  • It obviously has a "Controller".
  • It has some business logic.
  • It calls a credit card service.
  • It calls an email service.
  • It saves some information in DynamoDB.
  • It reads and writes to an AWS ElasticCache service.
  • It responds with JSON.

Considerations

An integration test will make a request which would be handled by "Controller", "Controller" will use business classes, some validation logic etc. Credit card and email services are invoked. Data is then saved in DynamoDB and ElasticCache and JSON response is returned.

  • This test will pass if all of it works. If it fails, can we tell what and where is the problem without looking around?
  • In order to execute the test, we have to incur a monetary cost. We are using the credit card and email services and also using few AWS services. We can use stub and actually we should be using that most of the times. But we would need a deployment environment, a stub environment and a lot of set up. Not all dependencies may have a stub readily available e.g. AWS or Azure services. Even then, Our controller, business classes etc. all are coming in the path of this test. We will still need to investigate or write explanatory tests to identify which component has failed.
  • If there is a cost associated with all your tests, how many tests can you afford? Will you be able to run them on every check-in?
  • With dependency on external systems, there will be a latency as well. How productive will it be to run them on every local build? Will all the services present on local environment? How long will your PR verification build take? How long will your commit build take?
  • We have to check state in all of these components.
  • We can't execute test until all the components have been implemented/configured. So parallelization is a bit hampered here.
  • Tests won't tell anything about the quality of code in most of the cases.

That said, by no means integration tests are bad. They help us to verify the interaction between two components. They ensure that the contract is intact between deployments. But maybe we could be a bit mindful while having them in place.

On the other hand, unit tests will focus only on a unit at a time. Say, "Controller" or one business class or credit card service caller. Dependencies and expectations can be mocked. How the unit behaves when the dependency behaves in specific fashion can thus be tested.

Considerations

  • If a test fails, it tells straightaway that the problem is with which unit (class/function).
  • Components can be developed in isolation and parallel. Only a contract (say Interface) is required to mock/fake the actual object.
  • We won't have to incur the cost of consuming external service.
  • There won't be latency (we talked about above).
  • ....... more here