Complexity
Complexity

Reputation: 5820

Unit Tests become Integration Tests with TDD

Assume that I'm writing an application which uses Test Driven Development. All the samples that I find are very small examples that try to explain how tests need to be written in TDD.

When you write a test in TDD, you write a very small piece of code whose purpose is to test a single piece of code, a single method, so a unit test.

After some time, a requirement from the client is received and you need to change your original code allowing it to accept much more arguments and splitting the method into multiple methods over multiple layers.

Let's say that logging is added when a failure occurs. What do I need to test then, the logging component separately, or chained together with the original method?

This means that the original unit test is in fact becoming an integration test as I'm testing multiple components together now.

Is this something that should be avoided, or how does one solve those kind of issues if needed?

Kind regards

Upvotes: 2

Views: 1448

Answers (4)

jab
jab

Reputation: 56

In addition to the other answers, you could have a look at the extended TDD cycle as defined in the book Growing Object-Oriented Software Guided by Tests. They are using acceptance tests to drive the inner loop of writing unit tests; depending on the situation, however, I found that you can also use integration tests to do that.

So no need to avoid them. What matters in my experience are the granularity and number of tests (less integration-, more unit tests).

Upvotes: 2

Raedwald
Raedwald

Reputation: 48674

There is no real fundamental difference between a unit test and an integration test.

A low level (unit) test of one of your classes will likely also exercise, and rely on, classes provided by your runtime environment or application framework. So your unit test could also be considered as an integration test of the combination of your code with the code of the runtime environment.

With no fundamental difference between them, there is no reason to be concerned if something once labelled "unit test" is now labelled "integration test".

Upvotes: 1

Dave Schweisguth
Dave Schweisguth

Reputation: 37617

TDD in the real world actually uses both unit tests and integration tests. Unit tests are seen in tutorials because it's easier to understand simple examples, but real applications need some integration tests. It's typical for the first test you write to be an integration test (see ).

However, integration tests are slow and hard to maintain (they touch more of the system than unit tests, so they change more frequently), so it's good to have only as many integration tests as needed and do as much of your testing with unit tests as is reasonable.

When requirements on a class cause it to become larger and you refactor the class into smaller classes, its unit tests are now integration tests. Address this by writing focused unit tests for the new classes and removing most of the old tests for the original class. It may be appropriate to leave behind one or a few of the old tests as integration tests. It also may be appropriate to rewrite some of the old tests to use test doubles (stubs, mocks, etc.) for what are now instances of other classes. Coincidentally, I recently wrote an answer about the mechanics of rewriting tests when you refactor a class out of another class.

Upvotes: 2

Channs
Channs

Reputation: 2101

TDD or not, the idea of an unit test is that you isolate an unit of the application and verify its code flows in isolation. An unit is typically a class and you would be looking at atleast one unit test per code branch of a method. E.g. If classA.methodA() has 3 branches, you will have 3+ unit tests for that method.

A true unit test injects the mocked/stubbed dependencies into the component, invokes the method to be tested and verifies its behavior and/or object state. Unit tests in principle should encourage you to improve the design of your source code in terms of loose coupling, separation of concern, etc. (SOLID principles).

Further, code coverage is a good measure of the quality of your unit tests, but striving for 100% isn't advised. Also, writing unit tests for every application layer is overkill; you would want to target layers that contain business logic to achieve a good return-of-investment. Lastly, do not write unit tests without having a Continuous Integration pipeline, since they tend to become stale very quickly.

On the contrary, when you start verifying two or more units as one test, it becomes an integration test since your test result is influenced by the success or failure of each unit. These tend to require more effort to setup the environment, could be flaky due to external dependencies and could be slow based on volume of transactions. These are definitely useful and you should aim for a code coverage based on your budget constraints. Integration tests should also be part of the CI/CD pipeline, but could be run less often than unit tests.

Hope this helps.

Upvotes: 1

Related Questions