Szukaj…
Prosta makieta
Mockito oferuje uniwersalny mehtod do tworzenia próbnych (nie-końcowych) klas i interfejsów.
Dependency mock = Mockito.mock(Dependency.class);
Tworzy to próbną instancję Dependency
niezależnie od tego, czy Dependency
jest interfejsem czy klasą.
Następnie możliwe jest wycieranie wywołań metod do tej próbki za pomocą notacji Mockito.when (x) .thenReturn (y).
Mockito.when(mock.possiblyBuggyMethod()).thenReturn("someString");
Tak więc wywołania Dependency.possiblyBuggyMethod()
po prostu zwracają "someString"
.
Istnieje inna notacja, która jest odradzana w większości przypadków użycia, ponieważ nie jest bezpieczna dla typów.
Mockito.doReturn("someString").when(mock).possiblyBuggyMethod()
Kpina z domyślnymi
Podczas gdy prosta próbka zwraca wartość null (lub domyślną dla prymitywów) do każdego wywołania, można zmienić to zachowanie.
Dependency mock = Mockito.mock(Dependency.class, new Answer() {
@Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
return "someString";
}
});
lub używając lambdas:
Dependency mock = Mockito.mock(Dependency.class, (Answer) invocationOnMock -> "someString");
Te przykłady zwracają „someString” do każdego wywołania, ale możliwe jest zdefiniowanie dowolnej logiki w metodzie odpowiedzi.
Kpiąc z klasy za pomocą adnotacji
Klasa testowana:
public class GreetingsService { // class to be tested in isolation
private UserService userService;
public GreetingsService(UserService userService) {
this.userService = userService;
}
public String getGreetings(int userId, LocalTime time) { // the method under test
StringBuilder greetings = new StringBuilder();
String timeOfDay = getTimeOfDay(time.getHour());
greetings.append("Good ").append(timeOfDay).append(", ");
greetings.append(userService.getFirstName(userId)) // this call will be mocked
.append(" ")
.append(userService.getLastName(userId)) // this call will be mocked
.append("!");
return greetings.toString();
}
private String getTimeOfDay(int hour) { // private method doesn't need to be unit tested
if (hour >= 0 && hour < 12)
return "Morning";
else if (hour >= 12 && hour < 16)
return "Afternoon";
else if (hour >= 16 && hour < 21)
return "Evening";
else if (hour >= 21 && hour < 24)
return "Night";
else
return null;
}
}
Działanie tego interfejsu będzie wyśmiewane:
public interface UserService {
String getFirstName(int userId);
String getLastName(int userId);
}
Załóżmy rzeczywistą implementację usługi UserService
:
public class UserServiceImpl implements UserService {
@Override
public String getFirstName(int userId) {
String firstName = "";
// some logic to get user's first name goes here
// this could be anything like a call to another service,
// a database query, or a web service call
return firstName;
}
@Override
public String getLastName(int userId) {
String lastName = "";
// some logic to get user's last name goes here
// this could be anything like a call to another service,
// a database query, or a web service call
return lastName;
}
}
Test Junit z Mockito:
public class GreetingsServiceTest {
@Mock
private UserServiceImpl userService; // this class will be mocked
@InjectMocks
private GreetingsService greetingsService = new GreetingsService(userService);
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testGetGreetings_morning() throws Exception {
// specify mocked behavior
when(userService.getFirstName(99)).thenReturn("John");
when(userService.getLastName(99)).thenReturn("Doe");
// invoke method under test
String greetings = greetingsService.getGreetings(99, LocalTime.of(0, 45));
Assert.assertEquals("Failed to get greetings!", "Good Morning, John Doe!", greetings);
}
@Test
public void testGetGreetings_afternoon() throws Exception {
// specify mocked behavior
when(userService.getFirstName(11)).thenReturn("Jane");
when(userService.getLastName(11)).thenReturn("Doe");
// invoke method under test
String greetings = greetingsService.getGreetings(11, LocalTime.of(13, 15));
Assert.assertEquals("Failed to get greetings!", "Good Afternoon, Jane Doe!", greetings);
}
}
„Szpieg” za częściowe kpiny
Adnotacji @Spy (lub metody ) można użyć do częściowego kpienia z obiektu. Jest to przydatne, gdy chcesz częściowo kpić z zachowania klasy. Załóżmy na przykład, że masz klasę, która korzysta z dwóch różnych usług i chcesz wyśmiewać tylko jedną z nich i korzystać z faktycznej implementacji drugiej usługi.
Uwaga dodatkowa: Chociaż z filozoficznego punktu widzenia nie uważałbym tego za „czysty test jednostkowy” w prawdziwym sensie, ponieważ integrujesz prawdziwą klasę, a nie testujesz swojej klasy w pełnej izolacji. Niemniej jednak może to być naprawdę przydatne w prawdziwym świecie i często używam go, gdy wyśmiewam bazę danych za pomocą implementacji bazy danych pamięci, dzięki czemu mogę używać prawdziwych DAO.
Class under test:
public class GreetingsService { // class to be tested in isolation
private UserService userService;
private AppService appService;
public GreetingsService(UserService userService, AppService appService) {
this.userService = userService;
this.appService = appService;
}
public String getGreetings(int userId, LocalTime time) { // the method under test
StringBuilder greetings = new StringBuilder();
String timeOfDay = getTimeOfDay(time.getHour());
greetings.append("Good ").append(timeOfDay).append(", ");
greetings.append(userService.getFirstName(userId)) // this call will be mocked
.append(" ")
.append(userService.getLastName(userId)) // this call will be mocked
.append("!");
greetings.append(" Welcome to ")
.append(appService.getAppName()) // actual method call will be made
.append(".");
return greetings.toString();
}
private String getTimeOfDay(int hour) { // private method doesn't need to be unit tested
if (hour >= 0 && hour < 12)
return "Morning";
else if (hour >= 12 && hour < 16)
return "Afternoon";
else if (hour >= 16 && hour < 21)
return "Evening";
else if (hour >= 21 && hour < 24)
return "Night";
else
return null;
}
}
Działanie tego interfejsu będzie wyśmiewane:
public interface UserService {
String getFirstName(int userId);
String getLastName(int userId);
}
Załóżmy rzeczywistą implementację usługi UserService
:
public class UserServiceImpl implements UserService {
@Override
public String getFirstName(int userId) {
String firstName = "";
// some logic to get user's first name
// this could be anything like a call to another service,
// a database query, or a web service call
return firstName;
}
@Override
public String getLastName(int userId) {
String lastName = "";
// some logic to get user's last name
// this could be anything like a call to another service,
// a database query, or a web service call
return lastName;
}
}
Zachowanie tego interfejsu nie będzie wyśmiewane:
public interface AppService {
String getAppName();
}
Załóżmy rzeczywistą implementację AppService
:
public class AppServiceImpl implements AppService {
@Override
public String getAppName() {
// assume you are reading this from properties file
String appName = "The Amazing Application";
return appName;
}
}
Test Junit z Mockito:
public class GreetingsServiceTest {
@Mock
private UserServiceImpl userService; // this class will be mocked
@Spy
private AppServiceImpl appService; // this class WON'T be mocked
@InjectMocks
private GreetingsService greetingsService = new GreetingsService(userService, appService);
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testGetGreetings_morning() throws Exception {
// specify mocked behavior
when(userService.getFirstName(99)).thenReturn("John");
when(userService.getLastName(99)).thenReturn("Doe");
// invoke method under test
String greetings = greetingsService.getGreetings(99, LocalTime.of(0, 45));
Assert.assertEquals("Failed to get greetings!", "Good Morning, John Doe! Welcome to The Amazing Application.", greetings);
}
@Test
public void testGetGreetings_afternoon() throws Exception {
// specify mocked behavior
when(userService.getFirstName(11)).thenReturn("Jane");
when(userService.getLastName(11)).thenReturn("Doe");
// invoke method under test
String greetings = greetingsService.getGreetings(11, LocalTime.of(13, 15));
Assert.assertEquals("Failed to get greetings!", "Good Afternoon, Jane Doe! Welcome to The Amazing Application.", greetings);
}
}
Ustaw prywatne pola w wyśmiewanych obiektach
W testowanej klasie możesz mieć prywatne pola, które nie są dostępne nawet przez konstruktor. W takich przypadkach można użyć odbicia, aby ustawić takie właściwości. To jest fragment takiego testu JUnit.
@InjectMocks
private GreetingsService greetingsService = new GreetingsService(); // mocking this class
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
String someName = "Some Name";
ReflectionTestUtils.setField(greetingsService, // inject into this object
"name", // assign to this field
someName); // object to be injected
}
Używam Sptring za ReflectionTestUtils.setField(Object targetObject, String name, Object value)
metoda tu uproszczenie, ale można użyć zwykły stary Odbicie Java, aby zrobić to samo.