GP Coder

Trang chia sẻ kiến thức lập trình Java

  • Java Core
    • Basic Java
    • OOP
    • Exception Handling
    • Multi-Thread
    • Java I/O
    • Networking
    • Reflection
    • Collection
    • Java 8
  • Design pattern
    • Creational Pattern
    • Structuaral Pattern
    • Behavior Pattern
  • Web Service
    • SOAP
    • REST
  • JPA
  • Java library
    • Report
    • Json
    • Unit Test
  • Message Queue
    • ActiveMQ
    • RabbitMQ
  • All
Trang chủ Java library Unit Test Mockito – Annotations

Mockito – Annotations

Đăng vào 28/03/2019 . Được đăng bởi GP Coder . 7283 Lượt xem . Toàn màn hình

Trong bài viết trước chúng ta đã cùng tìm hiểu về Mockito và cách viết JUnit với Mockito. Trong bài viết này chúng ta sẽ cùng tìm hiểu một số Annotation của Mockito như @Mock, @Spy, @Captor, @InjectMocks để viết test cho các behavior.

Nội dung

  • 1 Làm thế nào để sử dụng các Annotation của Mockito?
  • 2 Một số Annotation của Mockito

Làm thế nào để sử dụng các Annotation của Mockito?

Trước khi đi vào chi tiết từng Annotation của Mockito, chúng ta cùng xem một số cách để sử dụng Annotation của Mockito.

Sử dụng phương thức  MockitoAnnotations.initMocks(this), phương thức này phải được gọi trong @Before method.


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

Một cách khác để bật Annotation của Mockito là đánh dấu @RunWith(MockitoJUnitRunner.class) ở mức class, cách này thường được sử dụng.


@RunWith(org.mockito.junit.MockitoJUnitRunner.class)
public MockitoExampleTest {
	// Test methods
}

Ngoài các cách trên, chúng ta cũng có thể sử dụng Rule: MockitoJUnit.rule().


import java.util.List;

import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

public class MockitoExampleTest {

	@Rule
	public MockitoRule rule = MockitoJUnit.rule();

	@Mock
	private List<String> list;

	@Test
	public void shouldDoSomething() {
		list.add("gpcoder.com");
	}
}

Một số Annotation của Mockito

@Mock

Annotation @Mock được sử dụng để khởi tạo một mock object và inject giá trị này cho field này. Chúng ta không tạo ra các đối tượng thực sự, thay vào đó yêu cầu Mockito tạo ra một đối tượng giả cho class này, các phương thức của class này không được thực thi thực sự, do đó trạng thái của đối tượng không bị thay đổi.

Ngoài cách sử dụng @Mock trên mức field, chúng ta có thể sử dụng phương thức Mockito.mock(), nó cho cùng kết quả với @Mock. Cách sử dụng Annotation ngắn hơn, dễ hiểu hơn hơn và thường được sử dụng hơn.

Ví dụ sử dụng @Mock

Các bạn có thể xem thêm ở bài viết Giới thiệu Mockito.

Ví dụ sử dụng Mockito.mock(classToMock)


package com.gpcoder.mockito.mock;

import java.util.List;

import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

public class MockMethodTest {

	@Test
	public void test() {
		// Mock creation
		List<String> mockedList = Mockito.mock(List.class);

		// Using mock object
		mockedList.add("gpcoder.com");

		// Verifies certain behavior happened once
		Mockito.verify(mockedList).add("gpcoder.com");

		// Method add() is not really called,
		// it run on mocked object, so the size always is 0
		Assert.assertEquals(0, mockedList.size());

		// We can assign the size of mocked object
		Mockito.when(mockedList.size()).thenReturn(5);
		Assert.assertEquals(5, mockedList.size());
	}
}

Ví dụ các default value của một Mock object

DefaultValue.java


package com.gpcoder.mockito.mock;

import java.util.Collection;
import java.util.Optional;
import java.util.stream.Stream;

public interface DefaultValue {

	int getInt();

	Integer getInteger();

	double getDouble();

	boolean getBoolean();

	String getObject();

	Collection<String> getCollection();

	String[] getArray();

	Stream<?> getStream();

	Optional<?> getOptional();
}

DefaultValueOfMockObjectTest.java


package com.gpcoder.mockito.mock;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;

import java.util.Collections;

import org.junit.Test;
import org.mockito.Mockito;

public class DefaultValueOfMockObjectTest {

	@Test
	public void test() {
		DefaultValue demo = Mockito.mock(DefaultValue.class);
		assertEquals(0, demo.getInt());
		assertEquals(0, demo.getInteger().intValue());
		assertEquals(0d, demo.getDouble(), 0d);
		assertFalse(demo.getBoolean());
		assertNull(demo.getObject());
		assertEquals(Collections.emptyList(), demo.getCollection());
		assertNull(demo.getArray());
		assertEquals(0L, demo.getStream().count());
		assertFalse(demo.getOptional().isPresent());
	}
}

Thay đổi default value của mock object

Mockito cho phép chúng ta định nghĩa lại các default value của mock object thông qua các phương thức:

  • Mockito.mock(Class<T> classToMock, Answer defaultAnswer) : cho phép tạo một mock object với loại Answer được chỉ định. Loại Answer chỉ định cách xử lý mặc định nếu một stub method không được xác định.
  • Mockito.mock(Class<T> classToMock, MockSettings mockSettings) : cho phép tạo một mock object vói các setting được chỉ định. Các setting này có thể là defaultAnswer(), serializable(), name(), …

Các Answer được hỗ trợ bởi Mockito:

  • RETURNS_DEFAULTS : đây là default Answer nếu không được chỉ định. Nó trả về các giá trị “empty”, tức là null, 0, false, empty collection.
  • RETURNS_SMART_NULLS : tránh return null có thể gây ra lỗi NullPointerException. Nó trả về một SmartNull object. Phương thức test với object này vẫn bị fail, nhưng chúng ta có thể stack trace một unstubbed method chưa được gọi.
  • RETURNS_MOCKS : Mockito cố gắng return các empty value trước, sau đó đến mock object, cuối cùng sẽ return null. Chẳng hạn, đối với các String hoặc array, nếu nó không được stub thì Mockito sẽ trả về null. Nếu sử dụng loại Answer này, kết quả trả về là một emty string, empty array.
  • RETURNS_DEEP_STUBS : cho phép deep stub. Ví dụ, when(mock.getBar().getName()).thenReturn(“deep”);
  • CALLS_REAL_METHODS : gọi một real method nếu các method không được stub, tương tự như sử dụng @Spy.

Chi tiết về các loại Answer, MockSettings và ví dụ các bạn xem thêm trên document của Mockito.

@Spy

Annotation @Spy được sử dụng để wrap một object thật, có thể gọi xử lý thật sự ở object này, tuy nhiên chúng ta có thể spy một số phương thức trên đối tượng thật như với @Mock.

Ngoài cách sử dụng @Spy, chúng ta có thể sử dụng phương thức Mockito.spy(), nó cho cùng kết quả với @Spy.

Ví dụ sử dụng @Spy


package com.gpcoder.mockito.spy;

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

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.Spy;

@RunWith(org.mockito.junit.MockitoJUnitRunner.class)
public class SpyAnnotationTest {
	
	@Spy
	private List<String> spyList = new ArrayList<>();

	@Test
	public void test() {
		// Using mock object
		spyList.add("gpcoder.com");

		// Method add() is really called,
		// it run on real object, so the size is 1
		Assert.assertEquals(1, spyList.size());
		Assert.assertEquals("gpcoder.com", spyList.get(0));

		// We can assign the size of spy object
		Mockito.when(spyList.size()).thenReturn(5);
		Assert.assertEquals(5, spyList.size());
	}
}

Ví dụ sử dụng Mockito.spy()


package com.gpcoder.mockito.spy;

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

import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

public class SpyMethodTest {

	@Test
	public void test() {
		List<String> spyList = Mockito.spy(new ArrayList<>());

		// Using mock object
		spyList.add("gpcoder.com");

		// Method add() is really called,
		// it run on real object, so the size is 1
		Assert.assertEquals(1, spyList.size());
		Assert.assertEquals("gpcoder.com", spyList.get(0));

		// We can assign the size of spy object
		Mockito.when(spyList.size()).thenReturn(5);
		Assert.assertEquals(5, spyList.size());
	}
}

@InjectMocks

Trong một số trường hợp, chúng ta cần tạo một object test mà object này chứa các dependency khác. Vì vậy, chúng ta cần phải tạo các Mock/ Spy object cho các dependency và inject chúng vào đối tượng test. Để làm được điều này, chúng ta có thể sử dụng Annotation @InjectMocks.

@InjectMocks được sử dụng ở mức field, để đánh dấu các field này cần inject các dependency. Mokito cố gắng inject các giá trị cho các field này thông qua constructor, setter hoặc property injection. Nó sẽ không throw bất kỳ lỗi nào nếu không tìm được injection phù hợp.

Khả năng của @InjectMocks:

  • Tạo một real instance object để test.
  • Có thể gọi thực thi thực sự các phương thức được test.
  • Inject các dependency đã được khởi tạo bằng mock object (@Mock) vào object test.

Sự khác nhau giữa @Mock và @InjectMocks:

  • @Mock được sử dụng để tạo một mock object.
  • @InjectMocks được sử dụng để khởi tạo một real object và inject các dependency.

Ví dụ sử dụng @InjectMocks

UserDao.java


package com.gpcoder.mockito.injectmocks;

public interface UserDao {
	
	boolean createUser(String email);
}

UserService.java


package com.gpcoder.mockito.injectmocks;

public class UserService {

	private UserDao userDao;

	public UserService(UserDao userDao) {
		this.userDao = userDao;
	}

	public String createUser(String email) {
		boolean result = userDao.createUser(email);
		if (result) {
			// Send an email verify ...
			// Show a success message to end user ...
			return "SUCCESS";
		}
		// Send an error message to end user ...
		return "FAILED";
	}
}

UserServiceTest.java


package com.gpcoder.mockito.injectmocks;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

// @RunWith attaches a runner with the test class to initialize the mock data
@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {

	// Create a mock object
	@Mock
	private UserDao userDao;

	// Create a mock object and inject dependency (UserDao)
	@InjectMocks
	private UserService userService;

	@Test
	public void createUser_WhenEmailExisted_ReturnFailed() {
		// Define return value for method createUser()
		Mockito.when(userDao.createUser("existed@gpcoder.com")).thenReturn(false);

		// Use mock in test
		Assert.assertEquals("FAILED", userService.createUser("existed@gpcoder.com"));
	}

	@Test
	public void createUser_WhenEmailNotExisted_ReturnSuccess() {
		// Define return value for method createUser()
		Mockito.when(userDao.createUser("not_existed@gpcoder.com")).thenReturn(true);

		// Use mock in test
		Assert.assertEquals("SUCCESS", userService.createUser("not_existed@gpcoder.com"));
	}
}

Chúng ta cùng xem lại cách sử dụng @InjectMocks trong ví dụ trên:

  • Đầu tiên, chúng ta sử @Mock để tạo các mock object cho các dependency. Trong ví dụ này là UserDao.
  • Định nghĩa các behavior cho các mock object thông qua phương thức when() -> thenRetrun(). Các behavior này được gọi khi phương thức của test object được thực thi.
  • @InjectMocks : được sử dụng để tạo real instance object và inject các dependency trên cho instance này. Trong ví dụ này, một instance của UserService sẽ được tạo và được inject một UserDao mock object.

@Captor

Annotation @Captor được sử dụng để tạo một instance cho ArgumentCaptor. Lớp ArgumentCaptor cho phép truy cập các đối số của các phương thức được gọi trong quá trình verify. Vì vậy chúng ta có thể lấy được các đối số này và sử dụng chúng để test.

Ví dụ sử dụng @Captor


package com.gpcoder.mockito.captor;

import static org.hamcrest.Matchers.hasItem;

import java.util.Arrays;
import java.util.List;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class CaptorTest {

	@Captor
	private ArgumentCaptor<List<String>> captor;

	@Test
	public final void shouldHasListItem() {
		List<String> asList = Arrays.asList("gpcoder.com", "mockito", "junit");
		final List<String> mockedList = Mockito.mock(List.class);

		mockedList.addAll(asList);

		Mockito.verify(mockedList).addAll(captor.capture());
		Assert.assertEquals(0, mockedList.size()); // No changed because it is a mock object
		// Verify value on argument
		final List<String> capturedArgument = captor.getValue();
		Assert.assertEquals(3, capturedArgument.size());
		Assert.assertThat(capturedArgument, hasItem("gpcoder.com"));
	}
}

Tài liệu tham khảo:

  • https://static.javadoc.io/org.mockito/mockito-core/2.24.5/org/mockito/Mockito.html

 

5.0
05
Nếu bạn thấy hay thì hãy chia sẻ bài viết cho mọi người nhé! Và Donate tác giả

Shares

Chuyên mục: Unit Test Được gắn thẻ: JUnit, Mockito

Giới thiệu Mockito
Mockito – Control mock’s behavior

Có thể bạn muốn xem:

  • JUnit – Custom Hamcrest Matchers (18/03/2019)
  • Làm thế nào để chạy lại một failed Test trong JUnit? (21/03/2019)
  • Tổng hợp các bài viết về Unit Test trong Java (15/04/2019)
  • JUnit – Parameterized Test (08/03/2019)
  • JUnit – HTML Report với Surefire maven plugin (25/03/2019)

Bình luận

bình luận

Tìm kiếm

Bài viết mới

  • Clean code 13/01/2024
  • Giới thiệu CloudAMQP – Một RabbitMQ server trên Cloud 02/10/2020
  • Kết nối RabbitMQ sử dụng Web STOMP Plugin 19/06/2020
  • Sử dụng publisher confirm trong RabbitMQ 16/06/2020
  • Sử dụng Dead Letter Exchange trong RabbitMQ 13/06/2020

Xem nhiều

  • Hướng dẫn Java Design Pattern – Factory Method (97662 lượt xem)
  • Hướng dẫn Java Design Pattern – Singleton (97348 lượt xem)
  • Giới thiệu Design Patterns (87188 lượt xem)
  • Lập trình đa luồng trong Java (Java Multi-threading) (85899 lượt xem)
  • Giới thiệu về Stream API trong Java 8 (83408 lượt xem)

Nội dung bài viết

  • 1 Làm thế nào để sử dụng các Annotation của Mockito?
  • 2 Một số Annotation của Mockito

Lưu trữ

Thẻ đánh dấu

Annotation Authentication Basic Java Behavior Pattern Collection Creational Design Pattern Cấu trúc điều khiển Database Dependency Injection Design pattern Eclipse Exception Executor Service Google Guice Gson Hibernate How to Interceptor IO Jackson Java 8 Java Core JDBC JDK Jersey JMS JPA json JUnit JWT Message Queue Mockito Multithreading OOP PowerMockito RabbitMQ Reflection Report REST SOAP Structuaral Pattern Swagger Thread Pool Unit Test Webservice

Liên kết

  • Clean Code
  • JavaTpoint
  • Refactoring Guru
  • Source Making
  • TutorialsPoint
  • W3Schools Online Web Tutorials

Giới thiệu

GP Coder là trang web cá nhân, được thành lập với mục đích lưu trữ, chia sẽ kiến thức đã học và làm việc của tôi. Các bài viết trên trang này chủ yếu về ngôn ngữ Java và các công nghệ có liên quan đến Java như: Spring, JSF, Web Services, Unit Test, Hibernate, SQL, ...
Hi vọng góp được chút ít công sức cho sự phát triển cộng đồng Coder Việt.

Donate tác giả

Tìm kiếm các bài viết của GP Coder với Google Search

Liên hệ

Các bạn có thể liên hệ với tôi thông qua:
  • Trang liên hệ
  • Linkedin: gpcoder
  • Email: contact@gpcoder.com
  • Skype: ptgiang56it

Follow me

Copyright 2025 © GP Coder · All Rights Reserved · Giới thiệu · Chính sách · Điều khoản · Liên hệ ·

Share

Blogger
Delicious
Digg
Email
Facebook
Facebook messenger
Flipboard
Google
Hacker News
Line
LinkedIn
Mastodon
Mix
Odnoklassniki
PDF
Pinterest
Pocket
Print
Reddit
Renren
Short link
SMS
Skype
Telegram
Tumblr
Twitter
VKontakte
wechat
Weibo
WhatsApp
X
Xing
Yahoo! Mail

Copy short link

Copy link