12
votes

I just had a conversation with my lead developer who disagreed that unit tests are all that necessary or important. In his view, functional tests with a high enough code coverage should be enough since any inner refactorings (interface changes, etc.) will not lead to the tests being needed to be rewritten or looked over again.

I tried explaining but didn't get very far, and thought you guys could do better. ;-) So...

What are some good reasons to unit test code that functional tests don't offer? What dangers are there if all you have are functional tests?

Edit #1 Thanks for all the great answers. I wanted to add that by functional tests I don't mean only tests on the entire product, but rather also tests on modules within the product, just not on the low level of a unit test with mocking if necessary, etc. Note also that our functional tests are automatic, and are continuously running, but they just take longer than unit tests (which is one of the big advantages of unit tests).

I like the brick vs. house example. I guess what my lead developer is saying is testing the walls of the house is enough, you don't need to test the individual bricks... :-)

8
Regarding the brick example: bricks are mass-produced, their are all the same, which is different from functions or units.philant
Good point @philant. Not sure I agree with your lead dev. As mentioned in the comment, software units/modules aren't all the same and for all the reasons mentioned in the various answers, it is important and useful to have separate unit tests.Sid

8 Answers

17
votes

Off the top of my head

  • Unit tests are repeatable without effort. Write once, run thousands of times, no human effort required, and much faster feedback than you get from a functional test
  • Unit tests test small units, so immediately point to the correct "sector" in which the error occurs. Functional tests point out errors, but they can be caused by plenty of modules, even in co-operation.
  • I'd hardly call an interface change "an inner refactoring". Interface changes tend to break a lot of code, and (in my opinion) force a new test loop rather than none.
10
votes

unit tests are for devs to see where the code failed

functional tests are for the business to see if the code does what they asked for

6
votes

unit tests are for devs to see where the code failed

functional tests are for the business to see if the code does what they asked for

unit tests are checking that you've manufactured your bricks correctly

functional tests are checking that the house meets the customer's needs.

They're different things, but the latter will be much easier, if the former has been carried out.

4
votes

It can be a lot more difficult to find the source of problems if a functional test fails, because you're effectively testing the entire codebase every time. By contrast, unit tests compartmentalize the potential problem areas. If all the other unit tests succeed but this one, you have an assurance that the problem is in the code you're testing and not elsewhere.

1
votes

Bugs should be caught as soon as possible in the development cycle - having bugs move from design to code, or code to test, or (hopefully not) test to production increases the cost and time required to fix it.

Our shop enforces unit testing for that reason alone (I'm sure there are other reasons but that's enough for us).

0
votes

If you use a pure Extreme Programing / Agile Development methodology the Unit tests are always required as they are the requirements for development.

In pure XP/Agile one makes all requirements based on the tests which are going to be performed to the application

  • Functional tests - Generate functional requirements.
  • Unit tests - Generate functions or object requirements.

Other than that Unit testing can be used to keep a persistent track of function requirements.

i.e. If you need to change the working way of a function but the input fields and output keep untouched. Then unit testing is the best way to keep tracking of possible problems as you only need to run the tests.

0
votes

In TDD/BDD, unit tests are necessary to write the program. The process goes

failing test -> code -> passing test -> refactor -> repeat

The article linked also mentions the benefits of TDD/BDD. In summary:

  • Comes very close to eliminating the use of a debugger (I only use it in tests now and very rarely for those)
  • Code can't stay messy for longer than a few minutes
  • Documentation examples for an API built-in
  • Forces loose coupling

The link also has a (silly) walk-through example of TDD/BDD, but it's in PowerPoint (ew), so here's an html version.

0
votes

Assume for a second that you already have a thorough set of functional tests that check every possible use case available and you are considering adding unit tests. Since the functional tests will catch all possible bugs, the unit tests will not help catch bugs. There are however, some tradeoffs to using functional tests exclusively compared to a combination of unit tests, integration tests, and functional tests.

  • Unit tests run faster. If you've ever worked on a big project where the test suite takes hours to run, you can understand why fast tests are important.
  • In my experience, practically speaking, functional tests are more likely to be flaky. For example, sometimes the headless capybara-webkit browser just can't reach your test server for some reason, but you re-run it and it works fine.
  • Unit tests are easier to debug. Assuming that the unit test has caught a bug, it's easier and faster to pinpoint exactly where the problem is.

On the other hand, assuming you decide to just keep your functional tests and not add any unit tests

  • If you ever need to re-architect the entire system, you may not have to rewrite any tests. If you had unit tests, a lot of them will probably be deleted or rewritten.
  • If you ever need to re-architect the entire system, you won't have to worry about regressions. If you had relied on unit tests to cover corner cases, but you were forced to delete or rewrite those unit tests, your new unit tests are more likely to have mistakes in them than the old unit tests.
  • Once you already have the functional test environment set up and you have gotten over the learning curve, writing additional functional tests is often easier to write and often easier to write correctly than a combination of unit tests, integration tests, and functional tests.