Возникли проблемы с написанием модульного теста для объекта Kotlin

#unit-testing #object #kotlin #tdd

#модульное тестирование #объект #kotlin #tdd

Вопрос:

Учитывая логику TDD и пытаясь понять, как писать модульные тесты, у меня возникли проблемы с объектом Kotlin. Тест пройден, но я не уверен, действительно ли это правильный тест. Я пытаюсь убедиться, что вызывается метод Logger.i () и что он сохраняется в базе данных. Но на данный момент я застрял только на его вызываемой части.

Мой объект

 object Logger {
    fun i(tag: String, msg: String, tr: Throwable? = null): Int  {
        insertIntoLogDatabase(createLogModel("i", tag, msg, tr))
        return if (BuildConfig.DEBUG) Log.i(tag, msg, tr) else 0
    }

    private fun insertIntoLogDatabase(log: LogModel) {
        //Insert into Log DB
        logRepo.upsert(log)
    }

    private fun createLogModel(type: String, tag: String, msg: String, tr: Throwable?) = LogModel(0, type, tag, msg, if (tr != null) tr.message   "n"   tr?.stackTrace.contentToString() else null)

    fun setLogRepo(logRepo: LogRepository) {
        this.logRepo = logRepo
    }
}
  

при этом я знаю, что мне нужно вызвать Logger.setLogRepo(logRemp), чтобы предоставить регистратору доступ к репозиторию (и это работает)

Я застрял в том, что пытаюсь выполнить модульное тестирование вызова метода Log.i

У меня есть это

 @Mock
lateinit var log: Logger

@Before
fun setUp() {
    MockitoAnnotations.initMocks(this)

    Logger.setLogRepository(logRepo)
}

@Test
fun `log i failed`() {

    // When
    log.i("Test", "Test1")

    // Then
    verify(log, times(1)).i("Test", "Test1")
}
  

Я имею в виду, что это работает, но правильно ли это (моя интуиция подсказывает мне, что что-то не так, что я на самом деле не тестирую метод Logger.i ()

пожалуйста, сообщите.

Спасибо.

Ответ №1:

Как вы упомянули, вы должны проверить, что при регистрации данных они должны сохраняться в репозитории в нужном вам формате, и вы хотите в основном проверить, что, когда вы выполнили работу по отправке журнала в регистратор, он отправляется в репозиторий в правильном формате, и вы будете возражать против этого.

Итак, ваш тестовый пример будет выглядеть,

 @Mock
lateinit var logRepo: LogRepository

@Before
fun setUp() {
    MockitoAnnotations.initMocks(this)

    Logger.setLogRepository(logRepo)
}

@Test
fun `when an item is logged, it gets stored in the repository`()
{
  val expectedData= <valueThatShouldBeSentToRepo>

  Logger.i("Test", "Test1")

  verify(logRepo).upsert(expectedData)

}
  

Комментарии:

1. Я попробовал это, и я получаю следующие аргументы ошибки, которые отличаются! Требуется: logRepo.upsert(0: [Test] Test1 @ 2019-03-15T15:04:29.024); -> в com.mycomp.mytest.utilities.log.LogTest.logger я потерпел неудачу (LogTest.kt: 66) Фактический вызов имеет другие аргументы: logRepo.upsert(0: [Test] Test1 @ 2019-03-15T15:04:31.206);

2. В основном, потому что ожидаемые данные и Logger.i — это две разные вещи. значит, они не совпадают?

3. Вставьте свой класс LogModel, и если это не класс данных, то сделайте его классом данных

4. Это определенно класс данных 🙂 @Entity(tableName = "Logs") data class LogModel ( @NonNull @PrimaryKey(autoGenerate = true) var logID: Long = 0, @ColumnInfo(name = "type") var type: String, @ColumnInfo(name = "tag") var tag: String, @ColumnInfo(name = "msg") var msg: String, @ColumnInfo(name = "tr") var tr: String? ) { @ColumnInfo(name = "created_date") @TypeConverters(Converters::class) var createDate: LocalDateTime? = LocalDateTime.now() override fun toString(): String { return "$logID: [$tag] $msg @ $createDaten" } }

5. Поскольку для переменной CreateDate установлено время инициализации, оно будет отличаться от ожидаемого значения и фактического значения, поскольку ожидаемое значение создается первым, а фактическое значение создается после этого внутри logger. Это можно решить двумя способами: i) Исключить CreateDate из метода equals, переместив переменную CreateDate из конструктора внутрь класса, чтобы два объекта с одинаковыми данными, но с разным временем создания, были истинными.