Como ler um arquivo de texto de recursos em Kotlin?


94

Quero escrever um teste Spek em Kotlin. O teste deve ler um arquivo HTML da src/test/resourcespasta. Como fazer isso?

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") {
                ...
            }
        }
    }
})

Respostas:


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

30
Para mim, isso não funcionou, tive que mudar parathis::class.java.classLoader.getResource("/html/file.html").readText()
pavlos163 de

4
Para mim, ambas as opções funcionaram em um aplicativo Android (note o extra /em um deles, que deve ser removido no outro): this::class.java.getResource("/html/file.html").readText()ethis::class.java.classLoader.getResource("html/file.html").‌​readText()
Franco

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

28

outra solução ligeiramente 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)
}

Bom uso de uma função de extensão! Mas por que você usa uma função lambda aqui? Isso não faz muito sentido para mim. Além disso, a thisparte não funcionou para mim. Portanto, eu recomendo o seguinte:fun String.asResource(): URL? = object {}.javaClass.getResource(this)
Qw3ry

Gosto desse método de trabalhar nele, em que você declara o arquivo e, em seguida, trabalha no conteúdo desse arquivo. Preferência pessoal, eu acho. thisno exemplo acima se refere ao objeto string.
jhodges

isso é um abuso terrível da função de extensão. Carregar arquivos não é uma preocupação da classe String.
Ben

é neste contexto. Eu não disponibilizaria isso globalmente ou usaria fora das aulas de teste. Eu considero mais uma função de mapeamento aqui.
jhodges

25

Não tenho ideia de por que isso é tão difícil, mas a maneira mais simples que encontrei (sem precisar me referir a uma classe em particular) é:

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

E então passar um URL absoluto, por exemplo

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

é {}necessário? Por que não apenas javaClass.getResource(path).readText()?
andrewgazelka

1
javaClass deve ser chamado em um objeto de acordo com os documentos kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/java-class.html Se funcionar sem, então vá para sua vida :)
Russell Briggs

3
Uma desvantagem do método acima é que ele cria um novo objeto para cada acesso a recursos. Seria melhor armazenar o objeto fictício fora da função.
Russell Briggs

@RussellBriggs tbh Não acho que isso importe muito. O desempenho da criação de um objeto não é realmente um problema se você acessar o disco!
Qw3ry

13

Uma solução ligeiramente 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 algum motivo, isso não funcionou para mim. Apenas chamar explicitamente a classe funcionou. Apenas adicionando para outros. Acho que tem algo a ver com tornadofx
nmu

Depois de criar um arquivo de entrada de teste no /src/test/resources, this.javaClass.getResource("/<test input filename>")funcionou conforme o esperado. Obrigado pela solução acima.
jkwuc89

o que fazer, se fileContent não for String e eu não vou criar nenhum objeto fictício?
minizibi

1
A barra inicial antes do caminho parece obrigatória aqui, enquanto em Java eu ​​geralmente a omito.
cakraww

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)
}

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

4

Usando a classe de recursos da biblioteca do Google Guava :

import com.google.common.io.Resources;

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

é bom que Guave informe um nome de arquivo se o recurso não for encontrado - muito melhor para solucionar problemas
Nishi

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

0

Você pode achar a classe File útil:

import java.io.File

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

3
Essa resposta é enganosa. Isso não carrega um "recurso", mas carrega o arquivo diretamente do sistema de arquivos, ao invés do classpath. Não funcionará mais depois que o aplicativo for montado, pois você tentará se referir a arquivos não existentes, em vez de carregá-los do arquivo jar.
Ben

@ben Obrigado pelo seu comentário. A questão era sobre como ler o arquivo do recurso no teste kotlin Spek.
Krzysztof Ziomek

0

É assim que prefiro fazer:

fun getResourceText(path: String): String {
    return File(ClassLoader.getSystemResource(path).file).readText()
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.