Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Tomek Kaczanowski - Practical Unit Testing with JUnit and Mockito - 2013.pdf
Скачиваний:
228
Добавлен:
07.03.2016
Размер:
6.59 Mб
Скачать

Chapter 4. Test Driven Development

At the beginning of testing, things were simple. You wrote code, then you wrote tests to verify its validity. This seemed to be reasonable and brought good results. However after some time a few troublemakers ;) decided to turn things on their heads, and insisted on writing tests before implementation. This rather surprising idea got quite popular, and is claimed to bring even better results.

Initially, writing tests before writing the actual code was a way to verify it as soon as possible. As more and more people started to follow the test-first approach, they soon discovered that immediate verification is only a part of what you gain when writing tests first (and maybe not even the most important part). It turned out that thinking about the tests before any implementation has actually been written is a powerful design technique. Code not only worked better (thanks to being thoroughly tested), but also "looked and felt" better, in terms of its architecture, maintainability, and API ease of use.

Thus, test-first is now rather called Test Driven Development (TDD)1. There is still some discussion regarding the relation of TDD and test-first. However, it seems that the general understanding of these terms is that they really mean the same. Because of this, I will alternate between using one or other of the two terms throughout the book.

This book concentrates on testing aspects, even though you will get a decent dose of the TDD approach here. The best book on TDD that I know of is [freeman2009]. However, I would suggest that you gain some experience in testing techniques before you start reading it. And, by the way, even though it is really great, it won’t "teach" you TDD. Practice, practice, practice!

In this section we are going to take a closer look at what it means to write tests before implementation. Apart from giving some theoretical background, we will concentrate on practice. One important thing to remember is that even though the test-first approach will be demonstrated solely on unit tests, this does not mean that the applicability of TDD is confined to this particular kind of test! On the contrary, this approach can (and should) be used on every testing level.

But first, let us consider various answers to the following question: "when to write tests?".

4.1. When to Write Tests?

In the previous paragraphs, we have already mentioned two answers to this question:

write tests after implementation (test-last AKA code-first),

write tests before implementation (test-first).

Obviously, they are contradictory. You will have to choose which rule to follow, for a given piece of code. However, it is possible to use both of them for the whole coding process, choosing the more suitable one for each implementation task or code part.

In spite of being a huge supporter of the TDD approach, in Section 4.8 I will discuss some reasons for choosing test-last over test-first.

1It is also called Test Driven Design, which stresses the design aspect of this technique.

39

Chapter 4. Test Driven Development

But there is yet another answer to the "when to write tests?" question, which complements the two given previously: "write a test every time a bug is found". Let us describe each approach in more detail.

4.1.1. Test Last (AKA Code First) Development

In the "test last" approach, tests are written after the production code has been finished. It is a "traditional" approach to testing, predating the more recent "test first" approach.

Writing the tests after the code has advantages and disadvantages. The main advantage is that the tests are written when the functionality of the tested object is well understood. The main disadvantage is that the developer concentrates on testing the implementation (which he/she wrote only a few minutes earlier) instead of testing the interface (behaviour) of the SUT. This can lead to tests which:

are tightly coupled to the implementation (and as such will need to be rewritten every time it changes),

encourage developers to (sub)consciously select the sort of test cases they expect to pass successfully.

Additionally, when using the "test last" approach there is always a temptation to not write tests at all. Why bother, if you are pretty sure the code works as expected? Why bother, if you have run the thing and seen for yourself that the log messages are exactly as you wanted them to be? It requires a lot of selfdiscipline to write tests after you have a working code. And when the deadline comes, the temptation to save some time by avoiding this extra, seemingly unnecessary step, will grow. In my opinion, this is a serious reason to follow the test-first approach.

In some cases, i.e. when working with legacy code, the "test last" approach is the only possible one, as the code already exists.

4.1.2. Test First Development

This whole chapter is devoted to "test first" development, so let us start with a brief description of its most important characteristics.

Writing the tests before the actual code makes developers think about the behaviour of the tested object as opposed to its implementation (which does not exist at this point). It cuts down the functionality of each implemented class to the bare minimum determined by the test cases - no superfluous functionalities are added. It also results in a very high (if not 100%) level of code coverage (see Section 11.3), which, in general, is desirable.

This approach can be applied to any level of testing. In particular, it is very popular for and suited to unit tests.

4.1.3. Always after a Bug is Found

The first thing you should do after a bug has been found is to restrain your natural urge to fix it right away. If you fix it "just like that", you lose an opportunity to get rid of it once and for all. The bug may reappear later (because someone reverts the changes, for example when fixing another bug). If you write a test before fixing it, you will strengthen your safety net of tests, and the same bug will not come back.

So, no matter if you code test-first or test-last, you should write a test immediately after a bug is encountered. The test should expose the bug, that is, it should expect the right thing to happen, and at

40

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]