Question

If I already have integration test for my program, and they all passed, then I have a good feel that it will work. Then what are the reasons to write/add unit tests? Since I already have to write integration tests anyway, I will like to only write unit test for parts that not covered by integration tests.

What I know the benefit of unit test over integration test are

  • Small and hence fast to run (but adding new unit to test something is already tested by integration test means my total test suit get larger and longer to run)
  • Locate bug easier because it only test one thing (but I can start write unit test to verify each individual part when my integration test failed)
  • Find bug that may not be caught in integration test. e.g. masking/offsetting bugs. (but if my integration tests all passes, which means my program will work even some hidden bug exists. So find/fix these bugs are not really high priority unless they start breaking future integration tests or cause performance problem )

And we always want to write less code, but write unit tests need lots more code (mainly setup mock objects). The difference between some of my unit tests and integration tests is that in unit tests, I use mock object, and in integration tests, I use real object. Which have lots of duplication and I don't like duplicated code, even in tests because this add overhead to change code behavior (refactor tool cannot do all work all the time).

Was it helpful?

Solution

You've laid out good arguments for and against unit testing. So you have to ask yourself, "Do I see value in the positive arguments that outweigh the costs in the negative ones?" I certainly do:

  • Small-and-fast is a nice aspect of unit testing, although by no means the most important.
  • Locating-bug[s]-easier is extremely valuable. Many studies of professional software development have shown that the cost of a bug rises steeply as it ages and moves down the software-delivery pipeline.
  • Finding-masked-bugs is valuable. When you know that a particular component has all of its behaviors verified, you can use it in ways that it was not previously used, with confidence. If the only verification is via integration testing, you only know that its current uses behave correctly.
  • Mocking is costly in real-world cases, and maintaining mocks is doubly so. In fact, when mocking "interesting" objects or interfaces, you might even need tests that verify that your mock objects correctly model your real objects!

In my book, the pros outweigh the cons.

OTHER TIPS

I don't see much value in reeimplementing an existing integration-testcase as a unittest.

Integration tests are often much easier to write for non tdd legacy applications because usually the functionalities-to-be-tested are tightly coupled so testing units in isolation (=unittesting) can be difficuilt/expensive/impossible.

> Then what are the reasons to write/add unit tests?

In my opinion test-driven development is most effective if you write the unit tests before the actual code. This way the code that fulfills the tests becomes clearly separated with a minimum of external references that is easy testable.

If the code already exists without the unit tests it is usually a lot of extra work to write the unit tests afterwards because the code was not written for easy testing.

If you do TDD the code automatically is easy testable.

Integration tests should only verify that several components are working together as expected. Whether or not the logic of the individual components is accurate should be verified by unit tests.
Most methods have several possible execution paths; think of if-then-else's, input variables with unexpected or just plain wrong values, etc. Usually developers tend to think only about the happy path: the normal path that doesn't go wrong. But as far as those other paths are concerned, you have two options: you can let your end user explore those paths through the actions they take in the UI and hope they don't crash your application, or you can write unit tests that assert the behavior of those other paths and take action where necessary.

Some of the reasons you've pointed in your question are really important and by themselves could very well make the case in favor of unit testing, but YMMV. For instance, how often do you run your integrated test suite? My experience with integrated tests is that sooner or later they'll get so slow you won't run them every time you make a change and the time between inserting and detecting a bug will increase.

Also, a big mistake you may be making is trusting that

Find bug that may not be caught in integration test. e.g. masking/offsetting bugs.

is not important. Are you expecting that your users find the bugs for you? Trusting coverages obtained from integrated tests is dangerous in my opinion, you can very easily get a high % of coverage but in reality you are testing very little.

I guess the canonical reference against integrated tests are the posts of JBrains:

http://www.jbrains.ca/permalink/integrated-tests-are-a-scam-part-1

in case you haven't read them already.

Finally, IMO the feedback you can get from the unit tests for your design is invaluable. Judging a design by gut feeling and relying on integrated tests may also be a mistake.

If you expect ever to have to modify or refactor your code, having unit tests is essential. Unit tests exist not only to demonstrate bugs at the time the code is written, but to show when new bugs appear when more code is written.

Yes, it is much better to write your integration and unit tests first, but it there is a lot of value to having them even if they are written later.

Licensed under: CC-BY-SA with attribution
scroll top