Mockito – ile razy metoda została wywołana?

Mockito – ile razy metoda została wywołana?

W tym wpisie pokażę Ci w jaki sposób zaprojektować test jednostkowy z użyciem biblioteki Mockito! Na początek czym jest Mock? Mock to atrapa obiektu, czyli sztuczny obiekt który modelujemy po to aby zwracał metody potrzebne do przejścia danego testu. Mockito to biblioteka która została zaprojektowana do tworzenia atrap obiektów w Javie. Do dzieła! Tworzymy nowy projekt Apache Maven (bez konkretnego archetypu) i dołączamy bibliotekę Mockito i JUnit!

Plik pom.xml:

<dependencies>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>2.23.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>

Klasyka – tworzymy interfejs CalculatorService :

public interface CalculatorService {
    double add(double numberA, double numberB);
    double subtract(double numberA, double numberB);
    double multiply(double numberA, double numberB);
    double divide(double numberA, double numberB);
}

implementacja powyższego interfejsu – CalculatorServiceImpl :

public class CalculatorServiceImpl implements CalculatorService {
 
    public double add(double numberA, double numberB) {
        return numberA + numberB;
    }
 
    public double subtract(double numberA, double numberB) {
        return numberA - numberB;
    }
 
    public double multiply(double numberA, double numberB) {
        return numberA * numberB;
    }
 
    public double divide(double numberA, double numberB) {
        return numberA / numberB;
    }
}

Klasa MathApplication – posiada zależność do CaluclatorService:

public class MathApplication {
 
   private CalculatorService calcService;
 
   public void setCalculatorService(CalculatorService calcService){
      this.calcService = calcService;
   }
 
   public double add(double numberA, double numberB){		      
      return calcService.add(numberA, numberB);
   }
 
   public double subtract(double numberA, double numberB){
      return calcService.subtract(numberA, numberB);
   }
 
   public double multiply(double numberA, double numberB){
      return calcService.multiply(numberA, numberB);
   }
 
   public double divide(double numberA, double numberB){
      return calcService.divide(numberA, numberB);
   }
}

tworzymy przykładowy test jednostkowy:

@RunWith(MockitoJUnitRunner.class)
public class MathApplicationTester {
 
   @InjectMocks
   MathApplication mathApplication = new MathApplication();
 
   @Mock
   CalculatorService calcService;
 
   @Test
   public void testAdd(){
 
      when(calcService.add(10.0,20.0)).thenReturn(30.00);
 
      Assert.assertEquals(mathApplication.add(10.0, 20.0),30.0,0);
      Assert.assertEquals(mathApplication.add(10.0, 20.0),30.0,0);
      Assert.assertEquals(mathApplication.add(10.0, 20.0),30.0,0);
 
      verify(calcService, times(3)).add(10.0, 20.0);
   }
}

powyższy test definiuje zachowanie dla atrapy obiektu – Mocka. Jeśli wywołamy metodę:

calcService.add(10.0,20.0)

to zwróconym wynikiem przez obiekt mockowany ma być 30.

thenReturn(30.00)

Adnotacja @InjectMocks oznacza, że utworzony Mock (adnotacja @Mock) zostanie wstrzyknięty do klasy oznaczonej właśnie tą adnotacją.To ile razy wywołana została metoda add klasy CalcService sprawdzane jest za pomocą metody verify:

verify(calcService, times(3)).add(10.0, 20.0);

W wyniku test przeszedł prawidłowo!

Zobacz kod na GitHubie i zapisz się na bezpłatny newsletter!

.

2 Comments

  1. Według mnie to bardzo niefortunny przykład na użycie tej akurat możliwości Mockito.

    Po pierwsze CalculatorService jest złym przykładem interfejsu: operacja dodawania ma jedną poprawną implementację. Wydzielanie interfejsu na coś takiego to w najlepszym przypadku niepotrzebne mnożenie bytów i sugerowanie, że coś jest bardziej skomplikowane niż jest w rzeczywistości, a w najgorszym danie pola do napisania błędnej czy też niekompletnej implementacji.

    Po drugie metoda add() jest przykładem metody, której liczby wywołań w żadnym wypadku nie powinniśmy sprawdzać, ponieważ jest to metoda niezmieniająca stanu obiektu. Powinien nas interesować wyłącznie wynik wywołania tej metody, a nie ile razy była wywołana.

    Rozumiem, że to tylko uproszczony na potrzeby artykułu przykład, ale jest tak bardzo niedopasowany do intencji stosowania metody times() w Mockito, że niedoświadczony czytelnik może z niego wyciągnąć przez stosowanie analogii dużo złych wniosków: że w podobnych sytuacjach poprawne jest wydzielane interfejsu, weryfikowanie interakcji z tego typu klasami w taki sposób itp.

    Pozdrawiam

    • marcin warycha - javaleader.pl 9 lutego 2020 at 22:09

      Cześć Piotrze,

      Dzięki za konstruktywny feedback – to właśnie takie komentarze pozwalają dopracować JavaLeader.pl!, jest dokładnie tak jak piszesz to bardzo duże uproszczenie, napiszę w wolnej chwili bardziej adekwatny przykład. Jeszcze raz wielkie dzięki!

Leave a comment

Your email address will not be published.


*