Unit tests với Mockito

  1. Giới thiệu JUnit và Mockito

    JUnit là một framework dùng cho việc tạo các test case để kiểm thử các method của các đối tượng trong chương trình Java.

    Trong nhiều trường hợp, method được kiểm thử gọi đến những phương thức của một interface nào đó mà interface đấy chưa được implements bới bất kỳ class nào. Khi đó, trong Unit Test, ta cần giả lập các hàm của interface được sử dụng. Và Mockito là một framework thường dùng để giả lập kiểm thử, tạo giả một đối tượng cài đặt interface, giả lập lời gọi hàm đến đối tượng giả này và chỉ định kết quả trả lại cho lời gọi hàm giả lập đó.

  2. Các hàm hay sử dụng trong Mockito

    • Mockito.when(T methodCall): dùng để giả lập một lời gọi hàm nào đó được sử dụng bên trong method đang được kiểm thử.
    • Mockito.when(): thường đi kèm với .thenReturn(), .thenAnswer(), .thenThrow() để chỉ định kết quả trả lại.

    Ví dụ:

    Mockito.when(method_A()).thenReturn("demoValue");

    Mockito.when(method_B()).thenThrow(new Exception("demoError"));

    Mockito.when(method_C()).thenAnswer(new Answer<String>(){ public String answer(InvocationOnMock invocation){ String str = “demoNewAnswer”; return str; } });

    Các bạn chú ý kiểu dữ liệu trả về của method được mock, như ở ví dụ trên thì các method được mock đều có kiểu trả về là String. Nếu kiểu trả về thuộc kiểu khác, chẳng hạn Integer, chúng ta cần thay kiểu String bằng Integer ở 2 chỗ: khai báo Answer<String> và public String answer() thành Answer<Integer> và public Integer answer().

  • Các method Mockito.anyString(), Mockito.anyInt(), Mockito.any,… thường được dùng khi mock các method có tham số, mà bạn không xác định được giá trị của các tham số đó.

    Ví dụ:

    //Giả lập phương thức method_D với bất kỳ tham số có kiểu “int” thì trả về // kết quả là “1”: Mockito.when(method_D(anyInt())).thenReturn(1);

    //Giả lập phương thức method_E với bất kỳ tham số có kiểu “String” thì trả về kết quả là "demoValue": Mockito.when(method_E(anyString())).thenReturn("demoValue");

    //Giả lập phương thức method_F với bất kỳ tham số thuộc kiểu class XYZ thì trả về kết quả là "null": Mockito.when(method_F(any(XYZ.class))).thenReturn(null);

3. Demo

File Stock.java

public class Stock {
   private String stockId;
   private String name;
   private int quantity;

public Stock(String stockId, String name, int quantity){
  this.stockId = stockId;
  this.name = name;
  this.quantity = quantity;
}

public String getStockId() {
  return stockId;
}

public void setStockId(String stockId) {
  this.stockId = stockId;
}

public int getQuantity() {
  return quantity;
}

public String getTicker() {
  return name;
}

}

File: StockService.java

`public interface StockService {
   public double getPrice(Stock stock);
}`

File: Portfolio.java

import java.util.List;

public class Portfolio {
   private StockService stockService;
   private List<Stock> stocks;

   public StockService getStockService() {
      return stockService;
   }

   public void setStockService(StockService stockService) {
      this.stockService = stockService;
   }

   public List<Stock> getStocks() {
      return stocks;
   }

   public void setStocks(List<Stock> stocks) {
      this.stocks = stocks;
   }

   public double getMarketValue(){
      double marketValue = 0.0;

      for(Stock stock:stocks){
         marketValue += stockService.getPrice(stock) * stock.getQuantity();
      }
      return marketValue;
   }
}

File: PortfolioTester.java

package com.tutorialspoint.mock;

import java.util.ArrayList;
import java.util.List;

import static org.mockito.Mockito.*;

public class PortfolioTester {

   Portfolio portfolio;
   StockService stockService;

   public static void main(String[] args){
      PortfolioTester tester = new PortfolioTester();
      tester.setUp();
      System.out.println(tester.testMarketValue()?"pass":"fail");
   }

   public void setUp(){
      //Create a portfolio object which is to be tested
      portfolio = new Portfolio();

      //Create the mock object of stock service
      stockService = mock(StockService.class);

      //set the stockService to the portfolio
      portfolio.setStockService(stockService);
   }

   public boolean testMarketValue(){

      //Creates a list of stocks to be added to the portfolio
      List<Stock> stocks = new ArrayList<Stock>();
      Stock googleStock = new Stock("1","Google", 10);
      Stock microsoftStock = new Stock("2","Microsoft",100);

      stocks.add(googleStock);
      stocks.add(microsoftStock);

      //add stocks to the portfolio
      portfolio.setStocks(stocks);

      //mock the behavior of stock service to return the value of various stocks
      when(stockService.getPrice(googleStock)).thenReturn(50.00);
                                        when(stockService.getPrice(microsoftStock)).thenReturn(1000.00);

      double marketValue = portfolio.getMarketValue();
      return marketValue == 100500.0;
   }
}

Output:

Verify the Output:

pass