1. Введение
Kotlin и Java идут рука об руку. Это означает, что мы можем использовать огромное количество существующих библиотек Java в наших проектах на Kotlin.
В этой короткой статье мы увидим, как мы можем имитировать использование Mockito в Kotlin. Если вы хотите узнать больше о библиотеке, ознакомьтесь с этой статьей.
2. Настройка
Прежде всего, давайте создадим проект Maven и добавим зависимости JUnit и Mockito в pom.xml:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.3.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
Нам также нужно сообщить Maven, что мы работаем с Kotlin, чтобы он скомпилировал исходный код для нас. Ознакомьтесь с официальной документацией Kotlin для получения дополнительной информации о том, как настроить это в pom.xml.
3. Использование Mockito с Kotlin
Предположим, у нас есть реализация, которую мы хотим протестировать – LendBookManager. Этот класс имеет зависимость от сервиса, называемого BookService, который еще не реализован:
interface BookService {
fun inStock(bookId: Int): Boolean
fun lend(bookId: Int, memberId: Int)
}
Служба Book вводится во время создания экземпляра LendBookManager и используется дважды в методе оформления заказа, для которого нам нужно написать наш тест:
class LendBookManager(val bookService:BookService) {
fun checkout(bookId: Int, memberId: Int) {
if(bookService.inStock(bookId)) {
bookService.lend(bookId, memberId)
} else {
throw IllegalStateException("Book is not available")
}
}
}
Было бы сложно написать модульные тесты для этого метода, не имея возможности имитировать BookService – вот где пригодится Mockito.
Мы можем, используя всего две строки кода, создать макет интерфейса службы Book и дать ему команду возвращать фиксированное значение при вызове метода InStock():
val mockBookService = Mockito.mock(BookService::class.java)
Mockito.`when`(mockBookService. inStock(100)).thenReturn(true)
Это заставит экземпляр mockBookService возвращать значение true всякий раз, когда вызывается метод InStock() с аргументом 100 (обратите внимание, что нам пришлось экранировать метод when(), используя обратный флажок; это необходимо, поскольку when является зарезервированным ключевым словом в языке Kotlin).
Затем мы можем передать имитируемый экземпляр в LendBookManager во время создания экземпляра, вызвать метод, который мы хотим протестировать, и убедиться, что метод lend() был вызван в результате операции:
val manager = LendBookManager(mockBookService)
manager.checkout(100, 1)
Mockito.verify(mockBookService).lend(100, 1)
Мы можем быстро протестировать другой логический путь реализации нашего метода, который должен выдавать исключение, если нужной книги нет в наличии:
@Test(expected = IllegalStateException::class)
fun whenBookIsNotAvailable_thenAnExceptionIsThrown() {
val mockBookService = Mockito.mock(BookService::class.java)
Mockito.`when`(mockBookService. inStock(100)).thenReturn(false)
val manager = LendBookManager(mockBookService)
manager.checkout(100, 1)
}
Заметили, что для этого теста мы сказали mockBookService возвращать значение false при запросе, была ли книга с идентификатором 100 на складе. Это должно привести к вызову функции checkout(), вызывающей исключение IllegalStateException.
Мы используем ожидаемое свойство в аннотации @Test, указывающее, что мы ожидаем, что этот тест выдаст исключение.
4. Библиотека Mockito Kotlin
Мы можем сделать наш код более похожим на Kotlin, используя библиотеку с открытым исходным кодом под названием mockito-kotlin. Эта библиотека облекает некоторые функциональные возможности Mockito в свои методы, предоставляя более простой API:
@Test
fun whenBookIsAvailable_thenLendMethodIsCalled() {
val mockBookService : BookService = mock()
whenever(mockBookService.inStock(100)).thenReturn(true)
val manager = LendBookManager(mockBookService)
manager.checkout(100, 1)
verify(mockBookService).lend(100, 1)
}
Он также предоставляет свою версию метода mock(). При использовании этого метода мы можем использовать вывод типа, чтобы вызывать метод без передачи каких-либо дополнительных параметров.
Наконец, эта библиотека предоставляет новый метод whenever(), который можно использовать свободно, без необходимости в обратных тиках, как это было при использовании собственного метода when() Mockito.
Ознакомьтесь с их wiki для получения полного списка улучшений.
5. Заключение
В этом кратком руководстве мы рассмотрели, как настроить наш проект для совместного использования Mockito и Kotlin, и как мы можем использовать эту комбинацию для создания макетов и написания эффективных модульных тестов.
Оригинал статьи: https://www.baeldung.com/kotlin/mockito