Bài viết Câu hỏi About RongvangIT
profile Pic
0
0

Đăng ngày:

  73 Lượt xem

Sử dụng Mockito(Mockito-Kotlin) trong Android: Cách sử dụng cơ bản

Mockito-KotlinMockito

Đây là bản ghi chú cơ bản về cách sử dụng Mockito-Kotlin để tạo đối tượng kiểm thử (Stub, Mock, Spy).

Thêm thư viện

Vì các lớp và phương thức trong Kotlin không thừa kế hoặc ghi đè mặc định, bạn cần sử dụng mockito-inline để tránh lỗi khi thực hiện kiểm thử.

testImplementation "org.mockito.kotlin:mockito-kotlin:3.2.0"
testImplementation 'org.mockito:mockito-inline:3.11.2'

Khởi tạo với các chú thích @Mock@Spy

Thay vì sử dụng mock() hoặc spy(), bạn có thể sử dụng các chú thích @Mock@Spy để khởi tạo đối tượng Mock hoặc Spy. Để làm điều này, bạn cần thực hiện các bước sau:

  • Trước khi bắt đầu kiểm thử, thực hiện MockitoAnnotations.openMocks(this)
    • MockitoAnnotations.initMocks(this) đã bị đánh dấu là không khuyến khích.
  • Khi kiểm thử kết thúc, thực hiện close()
    • openMocks(this) tạo một đối tượng AutoCloseable.

Việc viết mã này trong mỗi lớp kiểm thử là khá phiền toái, vì vậy việc tạo một lớp kiểm thử cơ sở là tiện lợi.

open class SampleBaseTestCase {

    private lateinit var closeable: AutoCloseable

    @Before
    fun openMocks() {
        closeable = MockitoAnnotations.openMocks(this)
    }

    @After
    fun releaseMocks() {
        closeable.close()
    }
}
class SampleRepositoryTest: SampleBaseTestCase() {

    @Mock
    lateinit var dataSource: RemoteDataSource

    lateinit var repository: BookRepository

    @Before
    fun setUp() {
        // Vì đang kế thừa từ SampleBaseTestCase,
        // dataSource sẽ được khởi tạo tự động
        repository = SampleRepository(dataSource)
    }

    @Test
    fun sampleTest() {
        //...
    }
}

Stub

Mockito không cung cấp đối tượng kiểm thử đặc biệt cho Stub. Để tạo một Stub, bạn cần mock lớp đối tượng, sau đó cung cấp các phương thức Stub cho lớp đã được mock.

class StringFetcherTest: SampleBaseTestCase() {
    @Mock
    private lateinit var fetcher: StringFetcher

    @Before
    fun setUp() {
        // Khi fetcher.fetch() được gọi, trả về giá trị cụ thể
        whenever(fetcher.fetch(any())).thenReturn("Hello, world")

        // Thay đổi giá trị trả về tùy thuộc vào tham số đầu vào
        whenever(fetcher.fetch(any())).thenAnswer { invocation ->
            val author = invocation.arguments[0] as String
            return@thenAnswer when (author) {
                "福沢諭吉" -> "学問のすゝめ"
                "夏目漱石" -> "吾輩は猫である"
                "宮澤賢治" -> "雨ニモマケズ"
                else -> "Not Found"
            }
        }

        // Ném ngoại lệ khi tham số là chuỗi rỗng
        whenever(fetcher.fetch(eq(""))).thenThrow(
            IllegalArgumentException("ERROR")
        )
    }
}

Mock

Giả sử bạn có một lớp UserRepository như sau:

class UserRepository(private val webservice: Webservice) {
    fun getUser(id: Int): User {
        return webservice.getUser(id)
    }

    fun saveUser(user: User) {
        webservice.saveUser(user)
    }
}

Bạn có thể sử dụng @Mock cho Webservice và @InjectMocks cho UserRepository để tự động tạo mock và tiến hành injection.

class UserRepositoryTest: SampleBaseTestCase() {

    @Mock
    lateinit var webservice: Webservice

    @InjectMocks
    lateinit var userRepository: UserRepository

    @Test
    fun sampleTest() {
        val user = User(name = "Duy An")
        userRepository.saveUser(user)

        // Xác nhận rằng Webservice#saveUser(User) được gọi một lần
        verify(webservice, times(1)).saveUser(user)
        // Xác nhận rằng Webservice#saveUser(User) được gọi ít nhất một lần
        verify(webservice, atLeast(1)).saveUser(user)
        // Xác nhận rằng Webservice#saveUser(User) được gọi tối đa 5 lần
        verify(webservice, atMost(5)).saveUser(user)
        // Xác nhận rằng Webservice#getUser(User) không được gọi
        verify(webservice, never()).getUser(any())

        // Kiểm tra tham số truyền vào cho Webservice#saveUser(User)
        argumentCaptor<User> {
            verify(webservice, times(1)).saveUser(capture())
            assertEquals(firstValue.name, eq("Duy An"))
        }
    }
}

Spy

Để tạo Spy, bạn cũng có thể sử dụng chú thích @Spy. Việc sử dụng giống như Stub, nhưng bạn cần chú ý khi định nghĩa phương thức Stub.

class SampleSpyTest: SampleBaseTestCase() {

    @Spy
    lateinit var store: UserStore

    @Test
    fun spyTest() {
        // Dòng mã dưới sẽ gây lỗi
        // whenever(store.getFirstUser()).thenReturn(User("Duy An"))

        // Dòng mã dưới đây không gây lỗi
        doReturn(User("Duy An")).whenever(store).getFirstUser()

        val user = store.getFirst

User()
        assertEquals(user.name, "Duy An")
    }
}

Spy cho phép bạn cung cấp giá trị tùy ý cho đối tượng kiểm thử, giống như Stub. Tuy nhiên, Spy sử dụng thực sự instance (hoạt động như một loại proxy) nên khi gọi store.getFirstUser(), nó thực sự truy cập vào thuộc tính users của UserStore. Nếu users là một mảng trống khi bạn gọi nó, điều này sẽ gây ra lỗi. Để giải quyết điều này, Mockito cung cấp cú pháp tiền tố.

doReturn(User("Duy An")).whenever(store).getFirstUser()

Bằng cách này, bạn có thể trả về giá trị tùy ý trước khi phương thức thực sự được gọi. Ngoài doReturn(), bạn cũng có thể sử dụng doAnswer { ... } hoặc doThrow().

Kết luận

Trên đây tôi đã tóm tắt cách Sử dụng Mockito(Mockito-Kotlin) trong Android rồi. Hi vọng nó sẽ có ích cho công việc của anh em. Chào thân ái và quyết thắng

dev_pro_it
Đang làm IT tại Japan

Bình luận

Bài viết chưa có bình luận. Hãy trở thành người bình luận đầu tiên!
Sign up for free and join this conversation.
Sign Up
If you already have a RongvangIT account Login
Danh sách thư mục
Bắt đầu ngay với RồngVàngIT - nền tảng chia sẻ kiến thức lập trình tuyệt vời cho kỹ sư Việt Nam!

Hãy đăng nhập để sử dụng hàng loạt các chức năng tuyệt vời của RồngVàngIT !

  1. 1. Bạn sẽ nhận được các bài viết phù hợp bằng chức năng theo dõi tag và người dùng.
  2. 2. Bạn có thể đọc lại các thông tin hữu ích bằng chức năng lưu trữ nội dung.
  3. 3. Chia sẻ kiến thức, đặt câu hỏi và ghi lại quá trình trưởng thành của mình cùng RồngVàngIT !
Tạo tài khoản Đăng nhập
profile Pic