Should unit tests be written by the developer who wrote the code or someone else ? And how effective is writing units tests as a method of learning a new system ?
@CarlManaster has the right idea: It's the responsibility of the developer to:
- write a unit test,
- verify that it fails,
- implement it,
- verify that it succeeds,
- refactor the feature without failing the test, and finally
- refactor the test code
for every feature. The reason for each of these can be summarised as follows:
- Writing the test before the code ensures that the problem is sufficiently understood to actually do the right thing. You can still do exploratory programming, but TDD means you then have to throw away the result and start again by writing tests.
- If your test doesn't fail before implementing the feature, you typically are either testing the wrong thing or you don't understand the problem well enough.
- Implementing the actual feature is kind of the point :)
- Verifying that the test now succeeds makes sure that you have a short cycle to fix it.
- Refactoring is crucial to make sure the complexity of your application doesn't get out of hand. If you have tests for every feature refactoring them shouldn't break anything.
- Test code should be refactored for the same reason as above. This can be tricky since you need to make sure the tests still test the same things as before. One way to avoid breaking them is, for each test that you touch (directly or indirectly), to break it by changing for example a single character in the expected output, and running it to see that it fails for the right reason. Then just undo the change, and the test should still pass and still do the right thing.
Directly testing your own code is good form, and a system that encourages someone other than the developer to test it is a hazard, as the code may not even be testable without heavy modifications.
That said, expanding a project's unit test suite is a great way to get yourself on board with now it works.
TDD style test first coding works very well in a situation where you have a specific feature that has been described in detail that needs to be implemented, but it isn't going to help with more in depth architectural decisions.
Writing unit tests is part of the design process, whether you do TDD or not. So of course it's something to be done by the developer.
Integration tests, now these can be written by someone else.
Unit tests, however, are closely related to implementation and they affect the architecture.
Because even if we don't use TDD approach in strict sense, we should still design with testability in mind, so even writing unit tests post factum still has an impact on our code.
It's not only a method of learning, it gives us precious feedback on correctness and maintainability of our code. Furthermore, unit tests are a (quite valuable actually) form of documenting it.