在Kotlin中测试私有方法

时间:2018-08-26 22:10:54

标签: android kotlin tdd private

如何在Kotlin中测试私有方法?我尝试从@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)添加androidx.annotation.VisibleForTesting,但这并没有使我的函数私有化

这就是我的使用方式

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
fun doSomething() {}

[编辑]

我知道我不应该测试private方法,但是它现在总是微不足道的。那下面的情况呢?

我有一个CsvReader类

class CsvReader(private val inputStream: InputStream, private val separator: String = "\t") {
    fun read(): List<String> {
        return read(inputStream.bufferedReader())
    }
    private fun read(bufferedReader: BufferedReader): List<String> {
        val line = bufferedReader.use { it.readLine() } // `use` is like try-with-resources in Java
        return parse(line)
    }
    private fun parse(line: String): List<String> {
        return line.split(separator)
    }
}

我为此编写了测试

class CsvReaderTest {
    private val stream = mock<InputStream>()
    private val reader = CsvReader(stream)
    private val bufferedReader = mock<BufferedReader>()
    @Test
    fun read() {
        whenever(bufferedReader.readLine()).thenReturn("Jakub\tSzwiec")
        reader.read(bufferedReader) shouldEqual listOf("Jakub", "Szwiec")
    }
    @Test
    fun readWhenEmpty() {
        whenever(bufferedReader.readLine()).thenReturn("")
        reader.read(bufferedReader) shouldEqual listOf("")
    }
    @Test
    fun throwIOExceptionWhenReadingProblems() {
        whenever(bufferedReader.readLine()).thenThrow(IOException::class.java)
        val read = { reader.read(bufferedReader) }
        read shouldThrow IOException::class
    }
}

不幸的是,对于测试,我需要调用私有函数fun read(bufferedReader: BufferedReader): List<String>,因为在模拟File时,file.bufferedReader给出了NullPointerException Unable to mock BufferedWriter class in junit

3 个答案:

答案 0 :(得分:3)

对此只有一个一个答案:甚至不要尝试。

您编写源代码来传达意图。如果您做某事private,那么那是内部实现细节。下一秒可能会更改。

答案 1 :(得分:3)

像这样:

fun callPrivate(objectInstance: Any, methodName: String, vararg args: Any?): Any? {
        val privateMethod: KFunction<*>? =
            objectInstance::class.functions.find { t -> return@find t.name == methodName }

        val argList = args.toMutableList()
        (argList as ArrayList).add(0, objectInstance)
        val argArr = argList.toArray()

        privateMethod?.apply {
            isAccessible = true
            return call(*argArr)
        }
            ?: throw NoSuchMethodException("Method $methodName does not exist in ${objectInstance::class.qualifiedName}")
        return null
    }

您需要传递要调用该方法的对象的实例,方法名称和必需的参数

答案 2 :(得分:1)

你可以使用java反射:

测试方法:

  private fun printGreetings(name: String): String {
    return "Hello, $name"
  }

够了:

  private val classUnderTest = spyk(ClassUnderTest()) 

  @Test
    fun `should return greetings`() {
      val method = classUnderTest.javaClass.getDeclaredMethod("printGreetings", String::class.java)
      method.isAccessible = true
      val parameters = arrayOfNulls<Any>(1)
      parameters[0] = "Piotr"

      assertEquals("Hello, Piotr", method.invoke(classUnderTest, *parameters) )
  }