1

How do I test code in kotlin that does a readline like below:

import org.junit.jupiter.api.*
import org.junit.jupiter.api.Assertions.*
import java.io.*
fun foo() {
    val string="a b\nc d"
    var bais: ByteArrayInputStream=string.byteInputStream()
    val bis=BufferedInputStream(bais)
    //var l=bis.readLine() // no readline!
    // program uses just readline()
    var br: BufferedReader =BufferedReader(InputStreamReader(bais))
    var l=br.readLine()
    println(l) // works file
    val si=System.`in`
    println("System.`in` is ${si::class.simpleName}") // says it's a BufferedInputStream
}
fun main() {
    foo()
}
@TestInstance(TestInstance.Lifecycle.PER_CLASS) internal class T1KtTestCase {
    @Test fun testFoo() {
        // ?
    }
}
Ray Tayek
  • 9,841
  • 8
  • 50
  • 90
  • you are using java framework, in kotlin testing of `System` methods doesn't differ from java. check this one https://stackoverflow.com/questions/1119385/junit-test-for-system-out-println – Beloo May 04 '20 at 09:10
  • yes. looks like i am hosed as i need to mock readLine() – Ray Tayek May 04 '20 at 19:45

1 Answers1

2

You may add inputStream and outputStream as arguments to your function foo:

fun foo(inputStream: InputStream, outputStream: OutputStream) {
    val name = BufferedReader(InputStreamReader(inputStream)).readLine()
    PrintStream(outputStream).println("Hello, ${name.trim()}!")
}

fun main() {
    foo(System.`in`, System.out)
}

And then you can test your foo function as follows:

class Test {

    @Test
    fun testFoo() {
        val inputStream = "username".byteInputStream()
        val outputStream = ByteArrayOutputStream()
        foo(inputStream, outputStream)
        assertEquals(String(outputStream.toByteArray()), "Hello, username!\n")
    }

}
Vadik Sirekanyan
  • 3,332
  • 1
  • 22
  • 29
  • yes, but how do you test a piece of code that has a readLine() in it and uses system.in? – Ray Tayek May 04 '20 at 04:50
  • I've edited my answer, now I use `readLine()` method to read input. You cannot test `System.in` or it is too difficult to do. Ask yourself what you want to test. In my example it would be better to have separate `fun sayHello(name: String) { return "Hello $name" }` and test only that function. That's the point of unit testing, you should test small parts of your program. – Vadik Sirekanyan May 04 '20 at 09:15
  • kotlin has some extension functions to make this more readable. You can use `inputStream.reader().buffered()` and `"string".reader().buffered()` for example. I think if OPs function is dealing with strings he should use a `Reader` or `BufferedReader` though, rather than the raw `InputStream`. – Roger Keays Jun 23 '22 at 15:35