Добавил:
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

6.15. Exercises

In this section we have been discussing a number of aspects of advanced unit testing. Now it is time to practice some of these freshly acquired skills.

6.15.1. Design Test Cases: State Testing

A StringUtils class contains a reverse() method, with a signature as presented on Listing 6.51. List test cases, which would verify that this method really reverses the input String!

Listing 6.51. Signature of reverse Method

public String reverse(String s) { ... }

6.15.2. Design Test Cases: Interactions Testing

UserServiceImpl class contains the assignPassword() method, as presented on Listing 6.52. The method uses two collaborators to successfully perform its task: userDAO and securityService.

Listing 6.52. assignPassword() method

private UserDAO userDAO;

private SecurityService securityService;

public void assignPassword(User user) throws Exception {

String passwordMd5 = securityService.md5(user.getPassword()); user.setPassword(passwordMd5);

userDAO.updateUser(user);

}

Design the test cases for this method! Please note that this time you will have to think not only about the input parameters (user), but also about the values returned (or exceptions thrown!) by securityService

and userDAO.

6.15.3. Test Collections

Write a test for the trivial UserList class (shown in Listing 6.53), which will verify that:

an empty list of users is returned if no users have been added,

exactly one user is returned if only one has been added,

two users are returned if two have been added.

To complete this task write the assertions using some tool or other that you have not made use of yet. See Section 6.12 for inspiration.

142

Chapter 6. Things You Should Know

Listing 6.53. Testing collections - exercise

public class UserList {

private List<User> users = new ArrayList<User>();

public List<User> getUsers() { return users;

}

public void addUser(User user) { users.add(user);

}

}

6.15.4. Time Testing

Listing 6.54 presents a single test-dependent method. Use the method described in Section 6.11 to test its business logic.

Listing 6.54. Time-dependent method - exercise

public class HelpDesk {

public final static int EOB_HOUR = 17;

public boolean willHandleIssue(Issue issue) { Calendar cal = Calendar.getInstance();

int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);

if (Calendar.SUNDAY == dayOfWeek || Calendar.SATURDAY == dayOfWeek) { return false;

}

if (Calendar.FRIDAY == dayOfWeek) {

int hour = cal.get(Calendar.HOUR_OF_DAY); if (hour > EOB_HOUR) {

return false;

}

}

return true;

}

}

6.15.5. Redesign of the TimeProvider class

Let’s recall the Hello class after we had introduced a timeProvider collaborator to it (see the Listing 6.37 in the Section 6.11). The current version of this class fetches some data from the timeProvider (i.e. the current hour) and then makes some decision based on this returned data. This is not such a terrible thing, but it does break one important rule of good design: that we should preferably ask for results of calculations rather than data. We can fix it by changing the TimeProvider interface so that it answers the "is it morning?" question. After this, rewrite the test for the Hello class, and see if that has become any simpler!

In addition, write the implementation (with tests, of course!) of the TimeProvider interface! See how the test cases originally aimed at the Hello class now relate to the class implementing the TimeProvider interface!

143

Chapter 6. Things You Should Know

6.15.6. Write a Custom Matcher

Write a custom matcher - using the library of your choice - so that you are then in a position to write nicely readable assertions for the given OperatingSystem class, should you wish to:

Listing 6.55. The OperatingSystem class

public class OperatingSystem {

private int nbOfBits;

private String name;

private String version;

private int releaseYear;

// getters and setters omitted

}

An example of what you should achieve is presented below (written with FEST, but you can use Hamcrest to achieve a similar effect, if it suits you better):

Listing 6.56. Test of the OperatingSystem class

@Test

public class OperatingSystemTest {

private OperatingSystem os;

public void testUsingMatcher() { OperatingSystem min9 = new Mindows9();

assertThat(min9).is128bit().wasReleasedIn(2013).hasVersion(9);

}

}

Make sure you take care of any failed assertion messages in such a way that the cause of a failure is explicitly given.

Write some tests using your matcher, and decide whether it was worth the trouble of implementing it.

6.15.7. Preserve System Properties During Tests

Imagine you are testing code which modifies system properties30. Based on what you have learned in Section 6.8.2, write a custom rule which would preserve them. For example, if we assume that the system property with the key myKey has the value myValue before each test is executed, then it should also have an identical value after each test has finished, even if it was modified by the test code.

6.15.8. Enhance the RetryTestRule

In Section 6.8.2 we wrote a simple custom rule which allowed us to retry a failed test. As an exercise, please enhance it in the following way:

30http://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html

144

Chapter 6. Things You Should Know

this rule should affect only tests marked with the @Retry annotation31,

this rule should be configurable so that we can decide, for each test method, whether it should be rerun in cases of failure, and how many times it should be rerun after the test is considered to have failed.

The following provides an example of the enhanced RetryTestRule in action:

Listing 6.57. Enhanced RetryTestRule in action

public class EnhancedRetryTest {

@Rule

public RetryTestEnhancedRule retryTestRule = new RetryTestEnhancedRule();

static int firstTestCounter = 0; static int secondTestCounter = 0; static int thirdTestCounter = 0;

@Test

@RetryTest(retryNb = 2)

public void shouldFailOnSecondAttempt() { firstTestCounter++;

Assert.fail("failing " + firstTestCounter);

}

@Test

@RetryTest(retryNb = 3)

public void shouldFailOnThirdAttempt() { secondTestCounter++;

Assert.fail("failing " + secondTestCounter);

}

@Test

public void shouldNotBeRerun() { thirdTestCounter++;

Assert.fail("failing " + thirdTestCounter);

}

}

This test should be rerun once. This test should be rerun twice.

This test should not be rerun, because it is not marked with the @RetryTest annotation.

6.15.9. Make an ID Generator Bulletproof

As an additional exercise, please provide the implementation for an ID generator like that discussed in Section 6.10, that will pass the tests shown in Listing 6.33.

31http://docs.oracle.com/javase/tutorial/java/javaOO/annotations.html

145

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