Найти тему

Простое unit-тестирование Koin

Одна из проблем, с которой я недавно встретилась — как правильно протестировать, что коин создаст нужные объекты? И параллельно хотелось убедиться, что там single, а не factory. Причем делать это я хотела именно через unit-тестирование и тестить существующий рабочий модуль, а не создавать отдельный для тестов. Гугл вот почему-то для тестов просто дублирует все классы и их тестит, но я пока не понимаю это. Я же обязательно буду забывать добавлять изменения в дублирующий класс в тестах.

Много гуглила на эту тему, но в итоге мне помогли только исходники Koin, где они показывали как тестят: https://github.com/InsertKoinIO/koin. Вообще, в последнее время я поняла, что лучше не гуглить, а просто смотреть сами библиотеки. С вероятностью в 90% там найдется ответ.

Тестировать будем вот такой код:

Мы хотим убедиться, что будет создан именно Мурзик при создании iCat, и хотим точно знать, что Мурзик будет single.

Зависимость для тестов: "org.koin:koin-test:2.1.6"

В нашем тестовом классе надо создать правило для тестов и провайдер:

Я ставила Level.ERROR, потому что иначе падало исключение. О баге известно и это вариант, который советовали сами разработчики. В modules передаём названия модулей, которые хотим проверить.

И по сути это всё. Теперь можно тестить.

Вообще, в Koin есть удобный метод checkModules(). И он прекрасно работает до тех пор, если не встречается какая-то сложная инициализация. Например, я так и не смогла пока что правильно протестить с Firebase, потому что там есть init{ } и куча статических методов. И в этом случае checkModules всегда будет падать с исключением, даже если из всего модуля не получилось создать только один объект. Поэтому я всё тестирую отдельно, а не весь модуль сразу.

Перед тестовым методом инжектим объект, который хотим проверить:

private val murzik: ICat by inject()

Как выглядит сам метод:

3-7 строчки — мы проверяем, что в нашем модуле и правда есть нужный класс и что он не null.

9-10 строчки — мокаем параметры, которые нужны при создании Мурзика. Всё просто. Если для создания кота надо, например, ещё вызвать метод getName, то его можно вписать внутри фигурных скобок:

declareMock<MurzikName> { `when`(it.getName()).thenReturn("Murzik") }