Monday, August 7, 2017

Java, Java EE: Cách Dùng PowerMockito và Mockito

Junit test trong java là một phần không thể thiếu trong quá trình phát triển một ứng dụng java desktop application hoặc là java web application. Để đảm bảo các logic của các function chạy đúng như lúc ta thiết kế, hoặc đảm bảo trong quá trình refactor ta vô tình làm function ban đầu không còn đúng. Với những lí do đó junit test rất quan trọng. Nhưng trong quá trình viết test ta sẽ rất nhiều function mà ta không test được vơi junit test vd: Function kết nối database, liên quan đến database hoặc truy cặp internet... Khi đó ta sẽ giả lặp khi gọi đến những function đó thì nó sẽ trả về dữ liệu mà ta đã chuẩn bị trước đó, những thao tác đó ta gọi là mock data. Thư viện mock data mạnh nhất là Mockito và Powermockito ta sẽ tìm hiểu về cách cài đặt và sủ dụng của hai thư viện này.

I. Cách Dùng Mockito 

1. Thư viện cần thiết.

Ở đây mình xài maven project vì thế ta có thể import các dependancies sau trong file pom.
<dependency>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 <version>4.12</version>
</dependency>

<dependency>
 <groupId>org.mockito</groupId>
 <artifactId>mockito-all</artifactId>
 <version>1.9.5</version>
</dependency>

2. Import static thư viện

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

3. Xem một số ví dụ sau.

vd1: Ta mock hàm next của iterator sau đó ta sẽ xem dữ liệu sau khi ta gọi hàm next của iterator
@Test
public void hello() {
 // arrange
 Iterator i = mock(Iterator.class);
 when(i.next()).thenReturn("Hello").thenReturn("World");
 // act
 String result = i.next() + " " + i.next();
 // assert
 assertEquals("Hello World", result);
}
vd2: Tương tự với hàm compareTo ta cũng có thể làm như sau
@Test
public void with_arguments(){
 Comparable c=mock(Comparable.class);
 when(c.compareTo("Test")).thenReturn(1);
 assertEquals(1,c.compareTo("Test"));
}
vd3: Hoặc trong nhiều trương hợp ta muốn áp dụng cho tất cả các giá trị của một loại tham số nào đó ta có thể xài anyInt, anyString... trong mockito
@Test
public void with_unspecified_arguments(){
 Comparable c=mock(Comparable.class);
 when(c.compareTo(anyInt())).thenReturn(-1);
 assertEquals(-1,c.compareTo(5));
}

II. Cách xài PowerMock

Vậy thì Powmockito dùng để làm gì trong khi ta có Mockito rồi, ta sẽ cần Powermockito trong những trường hợp sau mà mockito sẽ không làm được vd như: Ta muốn mock static method, static class, finan class, private method, contructor vơi những trường hợp đặc biệt thế này ta chỉ có thể xài powermockito đê mock ngoài ra ta sẽ không làm được với Mockito.

1. Thư viện cần thiết.

Cách import thư viện tương tự như Mockito ta thêm các dependancies của mock
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.12</version>
</dependency>

<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-module-junit4</artifactId>
  <version>1.6.2</version>
</dependency>

<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-api-mockito</artifactId>
  <version>1.6.2</version>
</dependency>

2. Chạy với Powermock

@RunWith(PowerMockRunner.class)
@PrepareForTest({MyTest.class})
public class MyTest {

}

3. Ví dụ về Mock Constructor không có tham số.

@Test
public void saveEmployeeTest() throws Exception {
    PublicMethodTest publicMethodTest = new PublicMethodTest();

    Employee employeeMock = PowerMockito.mock(Employee.class);
    Services servicesMock = PowerMockito.mock(Services.class);

    publicMethodTest.setServices(servicesMock);

    PowerMockito.whenNew(Employee.class).withNoArguments().thenReturn(employeeMock);
    //PowerMockito.whenNew(Employee.class).withArguments(1, "mhdanh", 24).thenReturn(employeeMock);

    PowerMockito.doNothing().when(servicesMock).saveEmployee(employeeMock);

    publicMethodTest.saveEmployee();

    PowerMockito.verifyNew(Employee.class).withNoArguments();
    Mockito.verify(servicesMock).saveEmployee(employeeMock);
}

4. Ví dụ về Mock Private Method

PartialMockClass classUnderTest = PowerMockito.spy(new PartialMockClass());

// use PowerMockito to set up your expectation
PowerMockito.doReturn(value).when(classUnderTest, "methodToMock", "parameter1");

// execute public method contain private method
Assert.assertThat("ok mhdanh", classUnderTest.callPublishMethod());

// Use PowerMockito.verify() to verify result
PowerMockito.verifyPrivate(classUnderTest, times(2)).invoke("methodToMock", "parameter1");
Dùng Whitebox để test private method
MyClass instance = new MyClass();
Whitebox.invokeMethod(instance, "privateMethod", param1, param2,...);

Note: Sử dụng doReturn thay vì xài theo cách thông thường nếu dùng với spy
https://stackoverflow.com/questions/11620103/mockito-trying-to-spy-on-method-is-calling-the-original-method

5. Ví dụ về Mock Static Method

PowerMockito.mockStatic(Services.class);
PowerMockito.when(Services.heyMan()).thenReturn("mhdanh");
String okman = Services.heyMan();
Assert.assertEquals("mhdanh", okman);

6. Ví dụ về Mock Final Class

FinalClass finalClass = PowerMockito.mock(FinalClass.class);
PowerMockito.when(finalClass.myName("mhdanh")).thenReturn("mai huu danh");

String finaString = finalClass.myName("mhdanh");
Assert.assertEquals("mai huu danh", finaString);

7. Ví dụ về Mock Final Method

FinalClass finalClass = PowerMockito.mock(FinalClass.class);
PowerMockito.when(finalClass.yourName("mhdanh")).thenReturn("just me");

String finaString = finalClass.yourName("mhdanh");
Assert.assertEquals("just me", finaString);

8. Ví dụ về Mock Interface

IClass iClass = PowerMockito.mock(IClass.class);
PowerMockito.when(iClass.yourName("mhdanh")).thenReturn("just me");

String finaString = iClass.yourName("mhdanh");
Assert.assertEquals("just me", finaString);

9. Ví dụ về Whitebox.setInternalState

public class StudentService {
 private ClassService classService;
 /// ....
}

StudentService studentService = new StudentService();
ClassService classMock = PowerMockito.mock(ClassService.class);
Whitebox.setInteralState(studentService, "classService", classMock);

Note: Khi mock private, static, final, constructor chúng ta phải @PrepareForTest({ClassNameExample.class}) cho tất cả các class private, static, final, constructor 

Reference link
https://github.com/powermock/powermock/wiki/

No comments:

Post a Comment