Mateusz Wajnberger
Stub Mock Spy
W celu omówienia obiektów pomocniczych używanych w testach jednostkowych zajmiemy się serwisem, w którym użytkownicy przy założeniu konta podają swój adres. Tylko wtedy konto staje się aktywne. Dysponujemy klasą serwisową, która zwraca tylko i wyłącznie aktywne konta z repozytorium. Dodatkowo zakładamy, że nie mamy dostępu do kodu, który implementuje poniższy interfejs. Przy tym założeniu chcemy sprawdzić czy jest możliwe, abyśmy napisali jakieś sensowne metody testowe.
public class Address {
private String street;
private String number;
public Address(String street, String number) {
this.street = street;
this.number = number;
}
}
public class Account {
private boolean active;
private Address defaultDeliveryAddress;
private String email;
public Account() {
this.active =false;
}
public Account(Address defaultDeliveryAddress) {
this.defaultDeliveryAddress = defaultDeliveryAddress;
if(defaultDeliveryAddress != null) {
activate();
} else {
this.active = false;
}
}
public void activate() {
this.active = true;
}
public boolean isActive() {
return this.active;
}
public Address getDefaultDeliveryAddress() {
return defaultDeliveryAddress;
}
public void setDefaultDeliveryAddress(Address defaultDeliveryAddress) {
this.defaultDeliveryAddress = defaultDeliveryAddress;
}
}
public class AccountService {
private AccountRepository accountRepository;
public AccountService(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}
List<Account> getAllActiveAccounts() {
return accountRepository.getAllAccounts().stream()
.filter(Account::isActive)
.collect(Collectors.toList());
}
}
public interface AccountRepository {
List<Account> getAllAccounts();
}
Stub
Stub jest naszym pierwszym omawianym obiektem pomocniczym, który zawiera przykładową implementację imitującą działanie tej właściwej. Chcąc przetestować metodę zwracającą wszystkie aktywne konta, posłużymy się poniższą klasą, która implementuje nasz interfejs.
public class AccountRepositoryStub implements AccountRepository{
@Override
public List<Account> getAllAccounts() {
Address address = new Address("Kielecka", "73");
Account activeAccount = new Account(address);
Account inactiveAccount = new Account();
return Arrays.asList(activeAccount,inactiveAccount);
}
}
@Test
void getAllActiveAccounts() {
//given
AccountRepository accountRepositoryStub = new AccountRepositoryStub();
AccountService accountService = new AccountService(accountRepositoryStub);
//when
List<Account> accountList = accountService.getAllActiveAccounts();
//then
assertThat(accountList, hasSize(1));
}
Mock
Mock jest to obiekt, który symuluje działanie rzeczywistego obiektu i rzeczywistego kodu. Rozważmy sytuację, w której nie zostają zwrócone żadne dane. Dzięki zastosowaniu mocków nie musimy tworzyć kolejnej klasy stubowej, która zwracałaby pustą listę.
@Test
void getNoActiveAccounts() {
//given
AccountRepository accountRepository = mock(AccountRepository.class);
AccountService accountService = new AccountService(accountRepository);
given(accountRepository.getAllAccounts()).willReturn(Collections.emptyList());
//when
List<Account> accountList = accountService.getAllActiveAccounts();
//then
assertThat(accountList, hasSize(0));
}
Spy
Spy jest to połączenie prawdziwych obiektów oraz mocków. Jego działanie można śledzić oraz weryfikować podobnie jak to jest z obiektami mockowymi. W celu lepszego zobrazowania posłużymy się poniższym przykładem, w którym testowana jest metoda zwracająca sumę zamówienia. Dzięki temu, że jest to obiekt typu spy, możemy zweryfikować wywołanie konkretnych metod oraz dokonać stosowanej asercji.
public class Order {
private int price;
private int quantity;
public Order() {
}
public int getQuantity() {
return quantity;
}
public int getPrice() {
return price;
}
int sumPrice() {
return getPrice() * getQuantity();
}
}
@Test
void testTotalOrderPrice() {
//given
Order order = spy(Order.class);
given(order.getPrice()).willReturn(10);
given(order.getQuantity()).willReturn(2);
//when
int result = order.sumPrice();
//then
then(order).should().getPrice();
then(order).should().getQuantity();
assertThat(result, equalTo(20));
}