¿Cómo leer un archivo de texto de recursos en Kotlin?


94

Quiero escribir una prueba de Spek en Kotlin. La prueba debería leer un archivo HTML de la src/test/resourcescarpeta. ¿Cómo hacerlo?

class MySpec : Spek({

    describe("blah blah") {

        given("blah blah") {

            var fileContent : String = ""

            beforeEachTest {
                // How to read the file file.html in src/test/resources/html
                fileContent = ...  
            }

            it("should blah blah") {
                ...
            }
        }
    }
})

Respuestas:


111
val fileContent = MySpec::class.java.getResource("/html/file.html").readText()

30
Para mí, esto no funcionó, tuve que cambiarlo athis::class.java.classLoader.getResource("/html/file.html").readText()
pavlos163

4
Para mí, ambas opciones funcionaron en una aplicación de Android (observe el extra /en una de ellas, que debe eliminarse en la otra): this::class.java.getResource("/html/file.html").readText()ythis::class.java.classLoader.getResource("html/file.html").‌​readText()
Franco

19
val fileContent = javaClass.getResource("/html/file.html").readText()hace el trabajo aún más corto
Frank Neblung

28

otra solución ligeramente diferente:

@Test
fun basicTest() {
    "/html/file.html".asResource {
        // test on `it` here...
        println(it)
    }

}

fun String.asResource(work: (String) -> Unit) {
    val content = this.javaClass::class.java.getResource(this).readText()
    work(content)
}

¡Buen uso de una función de extensión! Pero, ¿por qué usa una función lambda aquí? Eso no tiene mucho sentido para mí. Además, la thispieza no me funcionó. Por eso recomiendo lo siguiente:fun String.asResource(): URL? = object {}.javaClass.getResource(this)
Qw3ry

Me gusta este método de trabajo en el que declaras el archivo y luego trabajas en el contenido de ese archivo. Preferencia personal, supongo. thisen el ejemplo anterior se refiere al objeto de cadena.
jhodges

eso es un abuso terrible de la función de extensión. La carga de archivos no es una preocupación de la clase String.
Ben

es en este contexto. No lo haría disponible a nivel mundial ni lo usaría fuera de las clases de prueba. Lo considero más una función de mapeo aquí.
jhodges

26

No tengo idea de por qué esto es tan difícil, pero la forma más sencilla que he encontrado (sin tener que referirme a una clase en particular) es:

fun getResourceAsText(path: String): String {
    return object {}.javaClass.getResource(path).readText()
}

Y luego pasar una URL absoluta, p. Ej.

val html = getResourceAsText("/www/index.html")

se {}requiere? ¿Por qué no simplemente javaClass.getResource(path).readText()?
andrewgazelka

1
Se debe llamar a javaClass en un objeto de acuerdo con los documentos kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/java-class.html Si funciona sin él, entonces vaya de por vida :)
Russell Briggs

3
Una desventaja del método anterior es que crea un nuevo objeto para cada acceso a los recursos. Sería mejor almacenar el objeto ficticio fuera de la función.
Russell Briggs

@RussellBriggs tbh No creo que eso importe mucho. El rendimiento de la creación de un objeto no es realmente un problema si tiene acceso al disco.
Qw3ry

13

Una solución ligeramente diferente:

class MySpec : Spek({
    describe("blah blah") {
        given("blah blah") {

            var fileContent = ""

            beforeEachTest {
                html = this.javaClass.getResource("/html/file.html").readText()
            }

            it("should blah blah") {
                ...
            }
        }
    }
})

Por alguna razón, esto no funcionó para mí. Solo funcionaba llamar explícitamente a la clase. Solo agregando para otros. Creo que tiene algo que ver con tornadofx
nmu

Después de crear un archivo de entrada de prueba /src/test/resources, this.javaClass.getResource("/<test input filename>")funcionó como se esperaba. Gracias por la solución anterior.
jkwuc89

¿Qué hacer si fileContent no es String y no crearé ningún objeto ficticio?
minizibi

1
La barra inclinada antes de la ruta parece obligatoria aquí, mientras que en Java generalmente la omito.
cakraww

5
val fileContent = javaClass.getResource("/html/file.html").readText()

5

Kotlin + Spring way:

@Autowired
private lateinit var resourceLoader: ResourceLoader

fun load() {
    val html = resourceLoader.getResource("classpath:html/file.html").file
        .readText(charset = Charsets.UTF_8)
}

5
private fun loadResource(file: String) = {}::class.java.getResource(file).readText()

4

Usando la clase de recursos de la biblioteca de Google Guava :

import com.google.common.io.Resources;

val fileContent: String = Resources.getResource("/html/file.html").readText()

es bueno que Guave informe un nombre de archivo si no se encuentra el recurso - mucho mejor para la resolución de problemas
Nishi

0

Puede encontrar útil la clase File:

import java.io.File

fun main(args: Array<String>) {
  val content = File("src/main/resources/input.txt").readText()
  print(content)
} 

3
Esta respuesta es engañosa. Eso no carga un "recurso" pero carga el archivo directamente desde el sistema de archivos, en lugar de la ruta de clases. Ya no funcionará después de ensamblar la aplicación, ya que tratará de hacer referencia a archivos no existentes, en lugar de cargarlos desde el archivo jar.
Ben

@ben Gracias por tu comentario. La pregunta fue sobre la lectura de archivos de recursos en la prueba de kotlin Spek.
Krzysztof Ziomek

0

Esta es la forma en que prefiero hacerlo:

fun getResourceText(path: String): String {
    return File(ClassLoader.getSystemResource(path).file).readText()
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.