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

Chapter 3. Unit Tests with no Collaborators

Listing 3.15. ClientTest with @Before annotation

public class ClientTest {

private Address addressA = new Address("street A"); private Address addressB = new Address("street B"); private Client client;

@Before

public void setUp() { client = new Client();

}

// the rest of the code identical to the previous listing

...

}

The @Before annotation makes JUnit execute this method before each test method is executed. Objects are only created in one dedicated method.

The order of method execution of code from Listing 3.15 is the following11:

setUp()

afterCreationShouldHaveNoAddress()

setUp()

shouldAllowToAddManyAddresses()

setUp()

shouldAllowToAddAddress()

JUnit offers three more similar annotations: @After, @BeforeClass and @AfterClass:

methods marked with the @After annotation are executed after each test method,

@BeforeClass and @AfterClass work exactly as @Before and @After, but on the class level (meaning, before/after any test of a test class is/was executed). Their use in unit tests is rather limited, but they are very handy for the higher level tests. Usually they are used to create some costly resources and clean them afterwards.

When it comes to @After and @AfterClass annotations, let me say that they are rarely used in unit tests. Your unit tests do not touch files, streams or databases which you would want to clean up (close, delete or remove) after the tests are finished.

3.9. Phases of a Unit Test

Now that we have encountered some unit tests we may take a closer look at their structure. As you will probably have noticed, a unit test takes care of three things: firstly, it creates an object to be tested (the SUT), along with other required objects (the SUT’s collaborators), then it executes the SUT’s methods, and finally it verifies the results. This pattern is so common for unit tests that such tests are often described as "arrange, act, assert" tests.

11In fact, the order of execution of the test methods is not guaranteed. What is guaranteed is that methods annotated with @Before will be invoked before each of the test methods.

33

Chapter 3. Unit Tests with no Collaborators

Table 3.3. Phases of a unit test

phase

explanation

 

 

 

creation of all objects (except for the SUT) that are necessary for test

arrange

execution

 

creation of the object whose functionality will be tested, and setting it in

 

 

some initial state

 

 

act

execution of SUT methods to be tested

 

 

assert

verification of the test results

 

 

The first phase relates to the preparation of a test fixture (see Section 3.8). As we have already discussed, this functionality is often (at least partially) contained within instance variables or utility methods shared by many tests, to avoid duplication of such set-up code across multiple test classes. You might have noticed that, in the table above, there is no "cleaning" step (or, to use JUnit nomenclature, tear-down method). Such a step is rarely used in unit tests where fresh objects are created at the beginning of every test method and no persisting storages (e.g. databases) are used.

Let us now analyze the ClientTest class which we have been discussing in the previous section. Table 3.4 shows how this test fits into the arrange, act, assert structure.

Table 3.4. The phases of ClientTest

phase

code example

 

 

arrange

Address addressA = new Address("street A");

 

Address addressB = new Address("street B");

 

Client client = new Client();

 

 

act

client.addAddress(addressA);

 

client.addAddress(addressB);

 

 

assert

assertEquals(2, client.getAddresses().size());

 

assertTrue(client.getAddresses().contains(addressA));

 

assertTrue(client.getAddresses().contains(addressB));

 

 

As we have seen in the previous examples, not all of the phases will necessarily be contained within a test method. For example, in the last version of the ClientTest class that we discussed (see Section 3.8.4), both instances of the Address class were created as private fields, and the SUT (an object of the Client class) was created within a setUp() method. However, this does not alter the fact that during the test execution the order of their creation was exactly as shown in Table 3.4.

Opinions are divided within the testing community as to what constitutes an adequate number of assertions per test method (see Section 7.4 for some discussion of this topic). However, it is recommended that all assertions within a single test method verify properties of a single object: the SUT. Asserting on many objects within a single test method is considered bad practice, and should be avoided!

3.10. Conclusions

In this section you have met JUnit and learned:

• about the default project structure that will be used throughout the book,

34

Chapter 3. Unit Tests with no Collaborators

how to write test classes and test methods,

how to run tests,

what assertions JUnit provides,

how to use parameterized tests,

how to verify expected exceptions,

how to use annotations for test fixture management.

What we have discussed in this section is good enough if you want to write really nice and useful unit tests. We have not gone into greater detail concerning these features, however, for two reasons: firstly, in many cases there are no more details, because testing frameworks (JUnit included) are rather simple, and secondly, we shall be adding a thing or two in subsequent parts of the book to what you have already learned about JUnit, and this will make more sense in the specific contexts that arise.

As you might expect, JUnit offers many other features which we have not yet covered. Some of them will be discussed in the ensuing sections, while others lie beyond the scope of this book, inasmuch as they have no real use in connection with unit tests. Once again, please make sure you at least browse the JUnit documentation, so that you know about its various capabilities.

If you were to ask me about the most important thing from this section, I would point to parameterized tests (see Section 3.6). Their correct use is hugely advantageous, allowing you to write very concise tests which cover many cases. The use of parameterized tests eliminates redundancy and adds to the readability of tests.

In the following sections we will be making use of the knowledge you have acquired here, so please make sure to practice it a little bit, before reading further.

35

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