Question
I want to write a Spek test in Kotlin and need to read an HTML file from the src/test/resources folder.
For example, if the file is located at src/test/resources/html/file.html, how can I load its contents into a String inside a test setup block?
class MySpec : Spek({
describe("blah blah") {
given("blah blah") {
var fileContent: String = ""
beforeEachTest {
// How do I read html/file.html from src/test/resources?
fileContent = ...
}
it("should blah blah") {
// assertions here
}
}
}
})
Short Answer
By the end of this page, you will understand how Kotlin tests access files in src/test/resources, how to read those files safely as text, and which resource-loading approach to use in real test code. You will also see practical examples for Spek and general Kotlin test setups.
Concept
In Kotlin and Java projects, files inside src/test/resources are not usually accessed by hardcoded filesystem paths during tests. Instead, they are placed on the test classpath by the build tool.
That means the usual way to read them is:
- locate the resource by its classpath path, such as
html/file.html - open it as a stream or URL
- convert it to a
String
This matters because classpath-based loading is more reliable than using direct paths like:
File("src/test/resources/html/file.html")
A direct path may work on your machine, but it can fail when:
- the working directory changes
- tests run in CI
- the project is packaged differently
- the code runs from a JAR or another environment
Using the class loader is the standard approach because it works with how test resources are actually provided to your code.
In Kotlin tests, the most common pattern is:
val text = javaClass.getResource("/html/file.html")!!.readText()
or:
val text = javaClass.classLoader
.getResourceAsStream("html/file.html")!!
.bufferedReader()
.use { it.readText() }
Both approaches read a file from the classpath. The important idea is that src/test/resources becomes the root of the resource path during test execution.
Mental Model
Think of src/test/resources as a special storage shelf that your test runner packs into a toolbox before your tests start.
You do not usually walk to the original shelf location by file path. Instead, you ask the toolbox:
- “Do you have
html/file.html?” - If yes, give me its contents.
So:
src/test/resources= the source shelf in your project- classpath = the packed toolbox available at runtime
getResource(...)= asking the toolbox for a named item
This is why resource loading uses names like html/file.html instead of full source-folder paths.
Syntax and Examples
The most common way to read a text resource in Kotlin is with getResource or getResourceAsStream.
Option 1: Using getResource(...).readText()
val fileContent = object {}.javaClass.getResource("/html/file.html")!!.readText()
What this does
getResource("/html/file.html")looks for the file on the classpath- the leading
/means the path starts from the classpath root !!means you expect the file to exist; if not, the test fails immediatelyreadText()reads the file contents into aString
Option 2: Using getResourceAsStream(...)
val fileContent = object {}.javaClass.classLoader
.getResourceAsStream("html/file.html")!!
.bufferedReader()
.use { it.readText() }
Why use this version?
This is a very common Java/Kotlin pattern and works well when you want explicit stream handling.
Spek example
class MySpec : Spek({
describe("blah blah") {
given("blah blah") {
var fileContent = ""
beforeEachTest {
fileContent = MySpec::class.java
.getResource("/html/file.html")!!
.readText()
}
it("should blah blah") {
println(fileContent)
}
}
}
})
Reusable helper function
If you read many test resources, create a helper:
fun readResource(path: String): String {
return object {}.javaClass.getResource(path)?.readText()
?: error("Resource not found: $path")
}
Usage:
val html = readResource("/html/file.html")
Step by Step Execution
Consider this example:
val text = MySpec::class.java
.getResource("/html/file.html")!!
.readText()
Here is what happens step by step:
-
MySpec::class.java- Gets the Java
Classobject forMySpec.
- Gets the Java
-
.getResource("/html/file.html")- Asks the class loader to find a resource named
html/file.htmlfrom the classpath root. - Because the file is in
src/test/resources/html/file.html, it should be found during test execution.
- Asks the class loader to find a resource named
-
!!- If the resource is not found,
getResource(...)returnsnull. !!turns that into an immediate failure with aNullPointerException.- In tests, this can be acceptable because a missing test resource should fail fast.
- If the resource is not found,
-
.readText()- Reads the entire file into a single
String.
- Reads the entire file into a single
-
The result is stored in
text- You can now use
textin assertions or parsing.
- You can now use
Full traceable example
val html = MySpec::class.java.getResource("/html/file.html")!!.readText()
println(html.length)
If the file contains:
<h1>Hello</h1>
Then:
- the resource is found
- the text
"<h1>Hello</h1>"is loaded html.lengthprints the number of characters in that string
Real World Use Cases
Reading test resources is common in many kinds of Kotlin projects.
Common use cases
- HTML testing
- load sample HTML pages and verify parsing or rendering logic
- JSON API testing
- store sample request/response payloads in
src/test/resources
- store sample request/response payloads in
- XML processing
- test XML parsing with realistic fixture files
- Template testing
- compare generated output with expected text files
- Data-driven tests
- keep test input files separate from code for readability
Example: JSON fixture
val json = MySpec::class.java.getResource("/responses/user.json")!!.readText()
Example: expected HTML output
val expectedHtml = MySpec::class.java.getResource("/html/expected.html")!!.readText()
Real Codebase Usage
In real projects, developers usually wrap resource loading in a small utility so tests stay clean.
Common patterns
1. Test fixture helper
object TestResources {
fun readText(path: String): String {
return TestResources::class.java.getResource(path)?.readText()
?: error("Missing resource: $path")
}
}
Usage:
val html = TestResources.readText("/html/file.html")
2. Fail-fast validation
Tests often use error(...) or requireNotNull(...) so a missing fixture gives a clear message.
val url = requireNotNull(MySpec::class.java.getResource("/html/file.html")) {
"Resource not found: /html/file.html"
}
val html = url.readText()
3. Keep fixtures realistic
Teams usually store:
- API payload samples
- rendered HTML snapshots
- CSV imports
- invalid input examples for error cases
4. Reuse across many test frameworks
The same resource-loading idea works in:
- Spek
- JUnit
- Kotest
- plain Kotlin test code
The framework usually does not change how classpath resources are loaded.
Common Mistakes
Here are common beginner mistakes when reading test resources in Kotlin.
1. Using the source folder path directly
Broken approach:
val text = java.io.File("src/test/resources/html/file.html").readText()
Why this is risky
- depends on the current working directory
- may fail in CI or different build setups
- does not use the classpath
Better
val text = MySpec::class.java.getResource("/html/file.html")!!.readText()
2. Forgetting the correct resource path
Broken approach:
val text = MySpec::class.java.getResource("file.html")!!.readText()
If your file is actually in html/file.html, this will not find it.
Better
val text = MySpec::class.java.getResource("/html/file.html")!!.readText()
3. Confusing getResource and getResourceAsStream
Both work, but they return different things:
getResource(...)returns aURL?getResourceAsStream(...)returns anInputStream?
Do not mix their APIs.
4. Ignoring nullability
Broken approach:
val text = MySpec::class.java.getResource("/html/file.html").readText()
This does not compile because getResource(...) can return null.
Better
val text = MySpec::class.java.getResource("/html/file.html")?.readText()
?: error("Resource not found")
5. Using the wrong leading slash
With Class.getResource(...):
"/html/file.html"means from the classpath root"html/file.html"may be treated relative to the class package
For test resources, using the leading / is usually clearer.
6. Not closing streams
If you use getResourceAsStream(...), use use {}.
val text = MySpec::class.java.classLoader
.getResourceAsStream("html/file.html")!!
.bufferedReader()
.use { it.readText() }
Comparisons
| Approach | Example | Best for | Notes |
|---|---|---|---|
Class.getResource(...).readText() | MySpec::class.java.getResource("/html/file.html")!!.readText() | Simple text fixtures | Very readable |
ClassLoader.getResourceAsStream(...) | classLoader.getResourceAsStream("html/file.html") | Stream-based reading | Common and explicit |
File("src/test/resources/...") | File("src/test/resources/html/file.html") | Quick local experiments | Less portable for real tests |
getResource vs getResourceAsStream
| Method | Returns | Path style | Good choice when |
|---|---|---|---|
getResource(...) | URL? | Often uses /html/file.html | You want concise text loading |
getResourceAsStream(...) | InputStream? | Usually html/file.html | You want stream handling or byte reading |
Relative vs absolute resource paths
| Path | Meaning |
|---|---|
"/html/file.html" | Start at the classpath root |
"html/file.html" | May be relative to the current class package when using Class.getResource(...) |
For beginners, an absolute classpath path is usually the safest option.
Cheat Sheet
Quick reference
Read a test resource as text
val text = MySpec::class.java.getResource("/html/file.html")!!.readText()
Read with class loader
val text = MySpec::class.java.classLoader
.getResourceAsStream("html/file.html")!!
.bufferedReader()
.use { it.readText() }
Safe version with custom error
val text = MySpec::class.java.getResource("/html/file.html")?.readText()
?: error("Resource not found: /html/file.html")
Rules to remember
src/test/resourcesbecomes part of the test classpath- use classpath paths like
html/file.html - with
Class.getResource(...),"/"means classpath root - prefer resource loading over direct filesystem paths in tests
- use
use {}when working with streams
Common paths
If file is here:
src/test/resources/html/file.html
Use one of these:
getResource("/html/file.html")
or
getResourceAsStream("html/file.html")
Good test pattern
fun readResource(path: String): String =
requireNotNull(MySpec::class.java.getResource(path)) {
"Missing resource: $path"
}.readText()
FAQ
How do I read a file from src/test/resources in Kotlin?
Use classpath resource loading, for example:
val text = MySpec::class.java.getResource("/html/file.html")!!.readText()
Why should I avoid File("src/test/resources/...") in tests?
Because it depends on the current working directory and is less reliable across environments.
What path should I use for a file in src/test/resources/html/file.html?
Usually either:
"/html/file.html"
with getResource(...), or:
"html/file.html"
with getResourceAsStream(...).
What happens if the resource does not exist?
getResource(...) or getResourceAsStream(...) returns null. You should handle that with requireNotNull, ?: error(...), or !! in tests.
Can I use this approach outside Spek?
Yes. The same pattern works in JUnit, Kotest, and regular Kotlin or Java code.
Is readText() suitable for HTML files?
Yes. HTML is plain text, so reading it into a String with readText() is a normal approach.
Should I use getResource or getResourceAsStream?
For simple text files, getResource(...).readText() is concise. If you want stream-based handling, use getResourceAsStream(...).
Mini Project
Description
Create a small Kotlin test utility that loads HTML fixture files from src/test/resources and checks whether expected text appears in them. This mirrors a common real-world testing pattern where sample HTML files are stored as fixtures and reused across multiple tests.
Goal
Build a reusable resource reader and use it to load an HTML file from src/test/resources, then verify its contents in a test.
Requirements
- Create an HTML file inside
src/test/resources/html/. - Write a Kotlin helper function that reads a resource into a
String. - Use the helper in a test to load the HTML file.
- Assert that the loaded content contains expected text.
Keep learning
Related questions
Accessing Kotlin Extension Functions from Java
Learn how Kotlin extension functions are compiled and how to call them correctly from Java with clear examples and common pitfalls.
Add a Maven Repository URL in Gradle Kotlin DSL (build.gradle.kts)
Learn how to add Maven Central and a custom Maven repository URL in Gradle Kotlin DSL using build.gradle.kts syntax.
Allow HTTP and HTTPS in Android 9 Pie with Network Security Configuration
Learn how Android 9 Pie handles cleartext HTTP traffic and how to allow HTTP and HTTPS safely using network security config.