網頁

2018/8/15

Mockito @Mock與@InjectMocks的差別

在單元測試(Unit Test)的物件生成套件Mockito中,@Mock@InjectMocks的區別如下。

  • @Mock的成員變數會被注入mock物件,也就是假的物件。
  • @InjectMocks標記的成員變數會被注入被標註@Mock的mock物件。

在撰寫測試類別時(例如UserServiceImplTest),如果被測試類別的某個方法(例如UserServiceImpl.getTeenUserList())中有呼叫外部的服務,例如UserDao.getUserListByAge(int from, int to),則我們就會使用@Mock來生成UserDao的mock物件(就是假的UserDao物件),而使用@InjectMocks來將被標註@Mock的mock物件注入被測試類別的物件中。

下面為被測試類別UserServiceImpl,及被測試的方法getTeenUserList()

UserServiceImpl.java

public class UserServiceImpl implements UserService {
    
    @Autowired
    private UserDao userDao;
    
    public List<User> getTeenUserList () {
        
        List<User> userList = userDao.getUserByAge(1, 18);
    
        return userList;
    }
}

下面為測試類別UserServiceImplTest,用來測試UserServiceImpl

UserServiceTest.java

import static org.junit.Assert.*;
import static org.mockito.Mockito.when;

public class UserServiceImplTest {
    
    @Mock
    private UserDao userDaoMock; // UserDao的mock物件
    
    @InjectMocks // 將有@Mock或@Spy的物件注入至此物件。在此範例就是將userDaoMock注入至UserService的userDao。
    private UserService userService = new UserServiceImpl(); 
    
    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this); // 用來初始化標註有@Mock或@Spy的物件
    }
    
    @Test
    public void testGetTeenUserList() {
        
        // 設定userDaoMock.getUserByAge(1, 18)會返回的結果
        List<User> userListMock = new ArrayList<User>();
        
        User user1 = new User();
        user1.setAge(10);
        User user2 = new User();
        user2.setAge(12);
        
        userListMock.add(user1);
        userListMock.add(user2);
        
        // 設定當userService.getTeenUserList()中執行到userDao.getUserByAge(1, 18)時,返回上面定義的userListMock
        when(userDaoMock.getUserByAge(1, 18)).thenReturn(userListMock); 
        
        List<User> userList = userService.getTeenUserList(); // 這邊才是實際測試userService.getTeenUserList()
        
        assertTrue(userList.get(0).getAge() <= 18); // 驗證結果是否如預期

    }     
}

上面的UserServiceImplTest.testGetTeenUserList()方法負責測試UserServiceImpl.getTeenUserList(),其主要目的是測試getTeenUserList()這個"單元",所以不需要測試userDao.getUserByAge(1, 18),因此我們假定呼叫外部的方法返回的結果是正確的。我們先將userDao.getUserByAge(1, 18)返回的結果設定好。

由於UserServiceImpl.getTeenUserList()這支程式僅呼叫了userDao.getUserByAge(1, 18),並沒有其他複雜的邏輯,所以在測試中只要有正確呼叫userDao.getUserByAge(1, 18)並返回結果則代表執行正確。


參考:

沒有留言:

張貼留言