Unit testy, Mockito

0

Cześć
Mam problem z testami, w których trzeba użyć Mockito.
Pokrótce mam zmockować GetRateFromUrlInterface, następnie zrobić atrapę tego interfejsu i ustawić stałe zachowanie w postaci określonego ratu i przetestować zwrot, np. jaką kwotę w gotówce zwrócę, jeśli chcę wymienić 100 zł na euro, przyjmijmy, że kurs 1 euro to 4zl. Na koniec test na wyjątek, czy wyjątek został poprawnie zwrócony.
Mam problem z ustawieniem stałego zachowania w postaci określonego ratu dla atrapy interfejsu i z testem na wyjątek.
Panowie prosiłbym o wskazówki.
Póki co zmockowałem GetRateFromUrlInterface, poniżej podsyłam kod


import java.io.IOException;
import java.math.BigDecimal;

public class CurrencyService implements CurrencyInterface {

    private GetRateFromUrlInterface getRateService;

    public CurrencyService(GetRateFromUrlInterface getRateService) {
        this.getRateService = getRateService;
    }

    @Override
    public BigDecimal exchange(String currencyFrom, String currencyTo, double amount) throws InvalidInputDataException, IOException {
        if (currencyFrom.equals("") || currencyTo.equals(""))
            throw new InvalidInputDataException("Przekazano błedne dane");

        BigDecimal rate = getRateService.getExchangeRateFromUrl(currencyFrom, currencyTo);
        return rate.multiply(BigDecimal.valueOf(amount));
    }
}


public interface GetRateFromUrlInterface {

    BigDecimal getExchangeRateFromUrl(String fromCurrencyMark, String toCurrencyMark) throws IOException;



--------------------------------------------------


public class CurrencyServiceTest {


    @Mock
    private GetRateFromUrlInterface getRateFromUrlInterfaceMock;
    
    @Before
    public void init() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void exchangeReturnTest() throws IOException, InvalidInputDataException {
        Mockito.when(getRateFromUrlInterfaceMock.getExchangeRateFromUrl("USD", "PLN"));

        CurrencyService currencyService = new CurrencyService(getRateFromUrlInterfaceMock);
        currencyService.exchange("USD", "PLN", 100);
        Mockito.verify(getRateFromUrlInterfaceMock).getExchangeRateFromUrl("USD", "PLN");


4
  1. Wyjdź, popraw i przyjdź jeszcze raz. double amount to dyskwalifikacja. Ma być BigDecimal amount.
  2. Masz idealny przykład funkcji /testu w którym nie ma potrzeby, nie powinno się, nie wolno używać Mockito. Więc: po co?
1

Zacząłeś ok, masz Mockito.when(getRateFromUrlInterfaceMock.getExchangeRateFromUrl("USD", "PLN")); a gdzie masz .then(...)? :) Przecież musisz określic CO się ma stać kiedy ktoś zawoła tą metodę.

Zgadzam sie z powyższym że to jest średnie miejsce na mockowanie czegokolwiek, bo na dobrą sprawę zamiast cudowania z mockito mógłbyć zrobić new CurrencyService((a,b)->BigDecimal.of(4.0));

0

Panowie wrzucam kod do sprawdzenia i prosiłbym bardziej doświadczonych osób o zerknięcie i komentarz.
Ogólnie występuje błąd java: package com.fasterxml.jackson.databind does not exist.
Jak sobie z tym poradzić??


public class CurrencyServiceTest {


    String from_Currency = "USD";
    String to_Currency = "PLN";
    String RATE = "4";
    double AMOUNT = 100;

    @Before
    public void init() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    void testExchange() throws InvalidInputDataException, IOException {
        GetRateFromUrlInterface getRateServiceMock = Mockito.mock(GetRateFromUrlInterface.class);
        //Inject mocked object to Currency service constructor
        CurrencyService currencyService = new CurrencyService(getRateServiceMock);
        //Create rate of BigDecimal type
        BigDecimal rate = new BigDecimal(RATE);
        //Set return value
        when(getRateServiceMock.getExchangeRateFromUrl(from_Currency, to_Currency)).thenReturn(rate);
        BigDecimal expected = new BigDecimal("83.000");
        BigDecimal actual = currencyService.exchange(from_Currency, to_Currency, AMOUNT);
        //Assert for actual and expected
        assertEquals(expected, actual);
    }

    @Test
    void testExchangeException1() throws InvalidInputDataException, IOException {
        //Mock the GetRateFromUrlInterface class using Mockito
        GetRateFromUrlInterface getRateServiceMock = Mockito.mock(GetRateFromUrlInterface.class);
        //Inject mocked object to Currency service constructor
        CurrencyService currencyService = new CurrencyService(getRateServiceMock);
        //Create rate of BigDecimal type
        BigDecimal rate = new BigDecimal(RATE);
        when(getRateServiceMock.getExchangeRateFromUrl(from_Currency, to_Currency)).thenReturn(rate);
        Exception exception = assertThrows(InvalidInputDataException.class, () -> {
            currencyService.exchange("", to_Currency, AMOUNT);
        });
        //Assert for exception message
        assertEquals("Przekazano b?edne dane", exception.getMessage());
    }

    @Test
    void testExchangeException2() throws InvalidInputDataException, IOException {
        //Mock the GetRateFromUrlInterface class using Mockito
        GetRateFromUrlInterface getRateServiceMock = Mockito.mock(GetRateFromUrlInterface.class);
        //Inject mocked object to Currency service constructor
        CurrencyService currencyService = new CurrencyService(getRateServiceMock);
        //Create rate of BigDecimal type
        BigDecimal rate = new BigDecimal(RATE);
        when(getRateServiceMock.getExchangeRateFromUrl(from_Currency, to_Currency)).thenReturn(rate);
        Exception exception = assertThrows(InvalidInputDataException.class, () -> {
            currencyService.exchange(from_Currency, "", AMOUNT);
        });
        //Assert for exception message
        assertEquals("Przekazano b?edne dane", exception.getMessage());

    }
}

2

Ogólnie występuje błąd java: package com.fasterxml.jackson.databind does not exist.

To może dodaj zależność do jacksona w pomie czy build.gradle czy czym sobie to tam ogarniasz?

4
  1. Dlaczego takie skomplikowane nazwy metod testowych masz?
  2. Nie za mało trafnych komentarzy?

np.

 //Assert for actual and expected
        assertEquals(expected, actual);

wyglądałoby bardziej pr0:

 //Assert for actual and expected - START
  assertEquals(expected, actual);
 //Assert for actual and expected - END 

a tak serio:
Ad.1) nazywanie metod testowych: test1,test2,test3,... - konwencja pozbawiona sensu.
Ad.2) komentarze, które masz, to niewiele wnoszą, a jedynie zaciemniają kod

Doczytaj o konwencjach nazewniczych dla testów. Randomowy lik z internetów: https://medium.com/@stefanovskyi/unit-test-naming-conventions-dd9208eadbea

3

@starsky859: jeszcze jedna uwaga: Co to za nazwa interfejsu

GetRateFromUrlInterface

Powinno być coś w stylu CurrencyRatesProvider. Ciebie jako użytkownika nie powinno interesowac czy to jest z RESTa, Soapa, czy dane sa dostarczane do implementacji przez Kafke etc.
@WeiXiao a Ty pisałeś że interface to abstrakcja :P

1 użytkowników online, w tym zalogowanych: 0, gości: 1