Jak czytać plik tekstowy z zasobów w Kotlinie?


97

Chcę napisać test Speka w Kotlinie. Test powinien odczytać plik HTML z src/test/resourcesfolderu. Jak to zrobić?

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

Odpowiedzi:


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

30
Dla mnie to nie zadziałało, musiałem to zmienić nathis::class.java.classLoader.getResource("/html/file.html").readText()
pavlos163

4
U mnie obie te opcje działały w aplikacji na Androida (zwróć uwagę na dodatek /w jednej z nich, który trzeba usunąć w drugiej): this::class.java.getResource("/html/file.html").readText()ithis::class.java.classLoader.getResource("html/file.html").‌​readText()
Franco

21
val fileContent = javaClass.getResource("/html/file.html").readText()wykonuje pracę jeszcze krócej
Frank Neblung,

1
Co dziwne, zawsze potrzebuję wiodącego cięcia. Np. Jeśli plik znajduje się w katalogu głównym zasobów, nadal musisz odnosić się do niego jako „/file.html”
Somaiah Kumbera

28

inne nieco inne rozwiązanie:

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

Niezłe użycie funkcji rozszerzenia! Ale dlaczego używasz tutaj funkcji lambda? Nie ma to dla mnie większego sensu. Ponadto thisczęść nie działała dla mnie. Dlatego polecam:fun String.asResource(): URL? = object {}.javaClass.getResource(this)
Qw3ry

Podoba mi się ta metoda pracy, w której deklarujesz plik, a następnie pracujesz nad zawartością tego pliku. Chyba osobiste preferencje. thisw powyższym przykładzie odnosi się do obiektu ciągu.
jhodges

to straszne nadużycie funkcji rozszerzenia. Ładowanie plików nie dotyczy klasy String.
Ben

jest w tym kontekście. nie udostępniłbym tego globalnie ani nie używałbym go poza klasami testowymi. Uważam to za bardziej funkcję mapującą.
jhodges

28

Nie mam pojęcia, dlaczego jest to takie trudne, ale najprostszy sposób, jaki znalazłem (bez konieczności odwoływania się do konkretnej klasy), to:

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

A następnie przekazując bezwzględny adres URL, np

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

jest {}wymagane? Dlaczego nie po prostu javaClass.getResource(path).readText()?
andrewgazelka

2
javaClass musi zostać wywołana na obiekcie zgodnie z dokumentacją kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/java-class.html Jeśli to działa bez, to idź na całe życie :)
Russell Briggs

3
Wadą powyższej metody jest to, że tworzy nowy obiekt dla każdego dostępu do zasobów. Byłoby lepiej przechowywać fikcyjny obiekt poza funkcją.
Russell Briggs

@RussellBriggs tbh Myślę, że to nie ma większego znaczenia. Wydajność tworzenia obiektów nie jest tak naprawdę problemem, jeśli masz dostęp do dysku!
Qw3ry

13

Nieco inne rozwiązanie:

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

            var fileContent = ""

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

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

Z jakiegoś powodu to nie zadziałało dla mnie. Tylko jawne wezwanie klasy zadziałało. Po prostu dodając dla innych. Myślę, że ma to coś wspólnego z tornadofx
nmu

Po utworzeniu pliku wejściowego testowej /src/test/resources, this.javaClass.getResource("/<test input filename>")działało zgodnie z oczekiwaniami. Dzięki za powyższe rozwiązanie.
jkwuc89,

co zrobić, jeśli fileContent nie ma wartości String i nie utworzę żadnego obiektu fikcyjnego?
minizibi

1
wiodący ukośnik przed ścieżką wydaje się tutaj obowiązkowy, podczas gdy w Javie zwykle go pomijam.
cakraww

6

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

Korzystanie z klasy zasobów biblioteki Google Guava :

import com.google.common.io.Resources;

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

Fajnie, że Guave zgłasza nazwę pliku, jeśli zasób nie zostanie znaleziony - znacznie lepsze do rozwiązywania problemów
Nishi

2

Oto sposób, w jaki wolę to robić:

fun getResourceText(path: String): String {
    return File(ClassLoader.getSystemResource(path).file).readText()
}

0

Może się przydać klasa File:

import java.io.File

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

3
Ta odpowiedź jest myląca. To nie ładuje „zasobu”, ale ładuje plik bezpośrednio z systemu plików zamiast ze ścieżki klas. Nie będzie już działać po złożeniu aplikacji, ponieważ spróbujesz odwołać się do nieistniejących plików, zamiast ładować je z pliku jar.
Ben

@ben Dzięki za komentarz. Pytanie dotyczyło odczytu pliku z zasobu w teście kotlin Spek.
Krzysztof Ziomek
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.