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

Chapter 5. Mocks, Stubs, Test Spies

No man is an island.

— John Donne Devotions upon Emergent Occasions (1624)

Classes are like people: only some of them thrive living in solitude. In the previous part of the book we took on board the very unrealistic assumption that the classes we test have a life of their own. It is time to get more real and dive into the troubled waters of relationships. As you will see, this has a serious impact on the testing techniques we will use.

Things are going to get interesting from now on. Pessimists will probably complain about things getting much harder, while optimists will be thrilled at the prospect of new, exciting challenges. Whichever one you are, read carefully, question what you learn, and practise a lot, because this is where the real challenges of unit testing begin.

Section 2.2 showed various types of interaction between an SUT and DOCs. We have already discussed how to deal with direct inputs and outputs. In this section we will be learning about ways to deal with the remaining SUT-DOCs interactions. We will do this by introducing test doubles, which will help us in many ways.

In general, test doubles are used to replace DOCs, where this allows us to:

gain full control over the environment in which the SUT is running,

move beyond state testing and verify interactions between the SUT and its DOCs.

Before we encounter the test doubles, we must learn about a tool which will greatly facilitate our task: it is time to meet Mockito. We will not spend too much time on theory right now – only introduce it briefly. Later, we will discover more about Mockito by watching it in action – it will be used in every example in this chapter. Anyway, some preliminary knowledge is required, so let us begin.

5.1. Introducing Mockito

Let me start by remarking that there are, at the very least, several good tools which could help us create and use test doubles in our test code. The choice is not an easy one, as they all have slightly different characteristics, which make them more suitable for different, specific scenarios. Moreover, some JVM languages - e.g. Groovy1 - come with some mocking capabilities built into the language itself, which further widens the field of choice. But because we are using Java, and because this is the beginning of our journey into the world of test doubles, Mockito seems like the best option.

Mockito is a relatively new framework2. It was originally based on EasyMock, a very successful and popular mocking framework. Mockito differs from its predecessor by promoting the use of test-spies over mocks, offering much cleaner API and very readable error messages. Thanks to the fact that it focuses on test-spies, it allows you to retain the natural test code order - arrange, act and assert - which you are already familiar with3. Its use is very intuitive – the learning curve is rather flat – but, at the

1See http://docs.codehaus.org/display/GROOVY/Groovy+Mocks

2Tools like Mockito are commonly called 'mock frameworks'. This term is slightly misleading, because Mockito is really a test-spy framework. However, you will hear it used a lot, so you had better get used to this flawed way of referring to it.

3Other mock-focused frameworks use a slightly different order, which is less friendly, especially if you are a beginner.

64

Chapter 5. Mocks, Stubs, Test Spies

same time, Mockito can serve you for a long time, as it is perfectly appropriate, even for complicated scenarios.

Fortunately, the syntax of Mockito is very simple to understand, so we can avoid lengthy explanations and simply enjoy its readability. Later on we will be learning more about it, but right now let us look at, and briefly explain, some code snippets.

As was the case with JUnit, this chapter introduces Mockito, but does not aim at being a complete reference source for this framework. Please consult the original documentation of Mockito to learn about all of its features.

5.1.1. Creating Test Doubles

You can think about a test double just as you would about a normal Java object. Its uniqueness results from the fact that it pretends to be something else: i.e. an object of some specific type4. The point is that you will have much more control over this imposter than you would over an object of the original class. This is why test doubles are so very useful in tests.

Listing 5.1 shows a very simple interface, which we will be using for the rest of this section.

Listing 5.1. Car interface

public interface Car {

boolean needsFuel();

double getEngineTemperature();

void driveTo(String destination);

}

Let us imagine that our SUT uses a DOC of type Car, and that, for the purpose of our tests, we need to fully control the behaviour of this DOC. Obviously, to be able to use a test double we must first create it (as mentioned earlier, test doubles are normal Java objects, after all). However, we do not use the new keyword to bring them to life. Instead, we ask Mockito, or another specialized framework, to create them. This is shown in Listing 5.2.

Listing 5.2. Creation of a test double

Car myFerrari = Mockito.mock(Car.class);

This code uses the org.mockito.Mockito class to create a test double. The static mock() method takes a class as an argument, and returns an object of this class. In the listing above, an object of the Car type is created. Mockito allows us to create test doubles of both classes and interfaces. If you were to try checking the type of object created, by means of the instanceOf operator, you would learn that this is a legal instance of the type Car. Listing 5.3 demonstrates this.

I will be using tests to demonstrate the various capabilities of Mockito.

4I use the term type to denote both classes and interfaces.

65

Chapter 5. Mocks, Stubs, Test Spies

Listing 5.3. myFerrari is of type Car

import org.junit.Test;

import static org.mockito.Mockito.*; import static org.junit.Assert.assertTrue;

public class FirstMockitoTest {

private Car myFerrari = mock(Car.class);

@Test

public void testIfCarIsACar() { assertTrue(myFerrari instanceof Car);

}

}

It is a normal test using JUnit @Test annotation.

The static import of the Mockito class makes the code more concise. Normal JUnit assertions are used within the test code.

As this test proves, the test-double object (myFerrari) is an instance of the type Car.

I will omit static imports of the org.mockito.Mockito class in the consecutive listings to make them shorter. However, do bear in mind that they are really all the time there.

Mockito uses the same method - mock() - to create all types of test double. No distinction between them is made at the time of their being created. The myFerrari object shown in Listing 5.2 can become a dummy, stub or test spy (we will discuss all of these in the next section). You, as a programmer, decide which role it plays, by expressing its expected behaviour and verifying (or not verifying) its actions.

The point of having a test double is to tell it what it should do. Now, if you were to use the myFerrari object, you would discover that it actually can do something without any intervention from your side. In particular, it is able to return some canned (default) values when we call its methods. Listing 5.4 demonstrates this5.

Listing 5.4. myFerrari returns default values

public class MockitoDefaultValuesTest {

private Car myFerrari = mock(Car.class);

@Test

public void testDefaultBehaviourOfTestDouble() {

assertFalse("new test double should return false as boolean", myFerrari.needsFuel());

assertEquals("new test double should return 0.0 as double", 0.0, myFerrari.getEngineTemperature());

}

}

This feature – the returning of some default values by test doubles - is specific to Mockito. In fact, this is just a manifestation of a certain deeper philosophy underlying this tool. Test doubles created by Mockito are considered to be 'nice', which means their behaviour is not strictly verified (by default). When using

5For complete information concerning default returned values please refer to Mockito’s Javadocs of org.mockito.internal.stubbing.defaultanswers package.

66

Chapter 5. Mocks, Stubs, Test Spies

Mockito, you must explicitly ask it to verify interactions. This has some deeper implications, discussion of which lies outside the scope of this book.

Other popular tools - i.e. EasyMock and JMock - take the opposite approach by using 'strict' test doubles by default. This difference between Mockito and the rest of the world is a source of endless, heated, but at the same time very interesting and informative debate. Please refer to Appendix C, Test Spy vs. Mock for some information on this topic.

5.1.2. Expectations

Of course, an object which can only return zeros and falseys is not much use to our tests. It is time to teach our myFerrari object to do as we say.

Let us say we need our myFerrari test double to return true when asked if it needs some fuel. Listing 5.5 shows how this can be done.

Listing 5.5. myFerrari returns what we want it to return

public class MockitoReturningDesiredValuesTest {

private Car myFerrari = mock(Car.class);

@Test

public void testStubbing() {

assertFalse("new test double should return false as boolean", myFerrari.needsFuel());

when(myFerrari.needsFuel()).thenReturn(true);

assertTrue("after instructed test double should return what we want", myFerrari.needsFuel());

}

}

This is what we already know - the default return value for the Boolean is false.

Now we tell myFerrari what to do when asked about the fuel. The when() method is another static

method of the org.mockito.Mockito class.

The behaviour has changed. This time myFerrari has returned true. All consecutive executions of

needsFuel() will also return true.

Listing 5.5 also illustrates a very nice feature of Mockito: the fact that code written using it is very readable. The crucial fragment:

when(myFerrari.needsFuel()).thenReturn(true)

can be read "just like that". Let us try it: "when someone asks myFerrari if it needsFuel() then it should return true". Voila!

Using a similar syntax, we can also instruct test doubles to throw exceptions. This is shown in Listing 5.6.

This feature of mocking frameworks - throwing exceptions on demand - is extremely useful for simulating all kinds of errors that can happen during the execution of your application. It is especially important when testing possible scenarios involving cooperation with some third-party components - e.g. databases or web services.

67

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