Одна из проблем, с которой я недавно встретилась — как правильно протестировать, что коин создаст нужные объекты? И параллельно хотелось убедиться, что там 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") }