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

Chapter 6. Things You Should Know

In general, you will probably not be expected to write all the code keeping reusability in mind. This would only be the case in some rare situations – i.e. when writing a "library", whose purpose is, precisely, to be reusable. What you are going to be paid for is to build this particular application – not to prepare your code so you can build any application with it. Of course, thinking about reusability is valuable, as it make you code much clean and easier to maintain, so not only your company, but also your own team will surely benefit from the lower maintenance effort. On the other hand, thinking about possible future use breaches the You Ain’t Gonna Need It (YAGNI) principle5. Try to be pragmatic about it.

And if you code every component with reusability in mind, your integrated application may perform suboptimally. For example, each component would repeat the same checks (e.g. null values checking). Does it really makes sense to check arguments for being null in the web layer, then pass them to the services layer and repeat the same checks, then pass them further to the DAO layer and perform the same checks? I don’t think so.

It is a different case with all "utility" classes. They should be context-free, because the chances of reusing them are much higher than for any other code you write. You should test them with special care, knowing that you cannot assume much about the context they will be used in.

As a case in point, the validator class, mentioned previously, falls into the "utility classes" category. As such, I would recommend preparing it for work in any context, without any assumptions about the arguments. That would mean it should be tested taking into account values not from 0 to 9 but from Integer.MIN_VALUE to Integer.MAX_VALUE. I guess that for this validator that would not mean a lot more work. In other cases, though, it might be different.

TIP: There are some ways to deal with methods which require many different sets of arguments in order to be properly tested. See Section 3.6 for what JUnit can offer in this respect. If this is something of great importance, you should also look for information on "pairwise testing"6 and tools like quickcheck7.

6.1.5. Not Only Input Parameters

So far, we have only discussed those sorts of case that have allowed us to freely set input parameters. However, in the real world not every input is passed as a method argument. We have already discussed the issues related to indirect inputs provided by DOCs. In case of such interactions of an SUT with DOCs, the same rules apply as were discussed previously. That is, we should write test cases for:

the normal behaviour of the DOC (i.e. that it returns reasonable values or throws reasonable exceptions),

the DOC returning boundary values,

the DOC returning unexpected values, i.e. throwing exceptions, that are unlikely to happen.

6.2. How to Fail a Test?

Apart from the assertion methods discussed in Section 3.4, there is also one more method in the Assert class that deserves our attention: fail(). It makes a test fail, and has overloaded versions which allow

5http://en.wikipedia.org/wiki/You_ain%27t_gonna_need_it 6See http://en.wikipedia.org/wiki/All-pairs_testing 7http://java.net/projects/quickcheck/pages/Home

102

Chapter 6. Things You Should Know

for an optional message to be specified. A test terminated with the fail() method is treated as if it had failed because of an unmet assertion. Historically, the fail() method was used for verifying expected exceptions. Currently, JUnit provides a better mechanism for this (see Section 6.4 for more information).

To conclude, you will rarely, if ever, find yourself using fail() methods in unit tests. However, in some circumstances it can be really useful, so it is good to know about its existence. One possible use of the fail() method is discussed in Section 6.4.

6.3. How to Ignore a Test?

Sometimes you want some of your tests to be ignored. It might happen that some functionality is still under development and the tests should not be executed yet. In such cases you can mark selected test methods with an @Ignore annotation.

Listing 6.1. Ignoring a test

import org.junit.Ignore;

public class IgnoreTest {

@Test

public void shouldBeRun() { System.out.println("shouldBeRun() is running!");

}

@Ignore @Test

public void shouldBeIgnored() { System.out.println("huh, not ignored?!");

}

}

Importing of the @Ignore annotation.

The test runner will skip all tests marked with the @Ignore annotation.

This message should not be printed.

After running, the following output should be printed:

Test 'com.practicalunittesting.chp06

.ignore.IgnoreTest.shouldBeIgnored' ignored shouldBeRun() is running!

In other cases you might want to achieve the same effect, but with the decision postponed until the runtime. JUnit offers a way to do this by providing the Assume class. As the JUnit JavaDocs says, the

Assume class provides a "set of methods useful for stating assumptions about the conditions in which a test is meaningful." Consider the following example:

103

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