12/08/2018, 15:33

Mockito từ A đến Z

Bài viết này cung cấp một hướng dẫn toàn diện để inject mock và mock method, và bao gồm cả method void. Hầu hết các class mà chúng ta sử dụng đều có dependency, và đôi khi, các method ủy thác một số công việc cho các method khác trong các class khác. Các class này là sự phụ thuộc của chúng ta. ...

Bài viết này cung cấp một hướng dẫn toàn diện để inject mock và mock method, và bao gồm cả method void.

Hầu hết các class mà chúng ta sử dụng đều có dependency, và đôi khi, các method ủy thác một số công việc cho các method khác trong các class khác. Các class này là sự phụ thuộc của chúng ta. Khi viết unit test cho các method như vậy, nếu chúng ta chỉ sử dụng JUnit, unit test của chúng ta cũng sẽ phụ thuộc vào các method đó. Chúng ta muốn các unit test của mình được độc lập với tất cả các phụ thuộc khác.

Ví dụ chúng ta muốn test method createCoinDetail trong class CoinDetailService và trong method createCoinDetail này, method lưu trữ của class coinDetailDAO được gọi ra. Chúng ta không muốn gọi thực hiện thực sự của method lưu trữ coinDetailDAO.addCoinDetail()( vì một vài lý do như sau :

  • Chúng ta chỉ muốn kiểm tra logic bên trong addCoinDetail() của service trong sự cô lập, ko có dependency.
  • Chúng ta có thể chưa implement nó.
  • Chúng ta không muốn việc test method addCoinDetail() của service không thành công nếu có một lỗi trong phương thức addCoinDetail() trong CoinDetailDao.

Vì vậy, chúng ta nên giả lập hành vi của các dependency. Mockito là những gì tôi sử dụng cho việc này, và trong bài này, chúng ta sẽ thấy làm thế nào để sử dụng hiệu quả Mockito để mock những dependency.

Mockito là một framework mock mà thị hiếu thực sự tốt. Nó cho phép bạn viết các test đẹp với API sạch sẽ và đơn giản. Mockito không lamf cho bạn khó hiểu hay nao núng bởi vì các test là rất dễ đọc và nó cung cấp các lỗi xác minh rõ ràng và dễ hiểu.

Quay lại ví dụ trên, làm thế nào để chúng ta mô phỏng sự phụ thuộc bằng cách sử dụng Mockito? Vâng, chúng ta có thể inject một mock đến các class đang được test thay vì implement thật trong khi chúng ta đang chạy test của mình!

Hãy xem xét một ví dụ về một class đang được test có depend vào CoinDetailDAO:

@Component
@Transactional
public class CoinDetailServiceImpl implements CoinDetailService {

    @Autowired
    private CoinDetailDAO coinDetailDAO;

    @Override
    public CoinDetail addCoinDetail(CoinDetail coinDetail) {
        return coinDetailDAO.addCoinDetail(coinDetail);
    }

    @Override
    public void createCoinDetail(CoinDetail coinDetail) {
        coinDetail.setCreatedDate(new Date());
        coinDetailDAO.createCoinDetail(coinDetail);
    }

    @Override
    public CoinDetail updateCoinDetail(CoinDetail coinDetail) {
        return coinDetailDAO.updateCoinDetail(coinDetail);
    }
}

Sau đây là test mocks dependency bằng cách sử dụng Mockito:

@RunWith(MockitoJUnitRunner.class)
public class CoinDetailServiceTest {

    @InjectMocks
    private CoinDetailServiceImpl coinDetailService;

    @Mock
    private CoinDetailDAO coinDetailDAO;
    
    @Before
    public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
    }
    @Test
    public void test() {
         //assertion here
    }
}

Chúng ta hãy nhìn vào vai trò của các annotation trong ví dụ trên.

  • @Mock sẽ tạo ra mock implementation cho dependency CoinAccountDAO
  • @InjectMocks là dành đối tượng đc test, ở đây chính là CoinAccountService
  • Đừng bỏ qua MockitoAnnotations.initMocks(this) ở setUp() nhé             </div>
            
            <div class=
0