sbt has a suite of integration tests, also known as scripted tests.
Scripted integration tests reside in **`sbt-app/src/sbt-test`** and are
written using the same testing infrastructure sbt plugin authors can
use to test their own plugins with sbt.
You can run the integration tests with the `sbt scripted` sbt
command. To run a single test, such as the test in
`sbt-app/src/sbt-test/project/global-plugin`, from the sbt shell run:
```bash
> scripted project/global-plugin
```
The scripted test framework lets you script a build scenario. It was written to test sbt itself on complex scenarios -- such as change detection and partial compilation.
How to create a scripted test
-----------------------------
### step 1: sbt-app/src/sbt-test
Make a directory structure `sbt-app/src/sbt-test/<test-group>/<test-name>`.
For example, `sbt-app/src/sbt-test/project/something`.
Create an initial build in `something`. Like a real build using sbt. I'm sure you already have several of them to test manually. Here's an example `build.sbt`:
Now, write a script to describe your scenario in a file called `test` located at the root dir of your test project.
```bash
# check if the file gets created
> packageBin
$ exists target/**/foo/foo_3-0.1.0-SNAPSHOT.jar
```
Here is the syntax for the script:
1.**`#`** starts a one-line comment
2.**`>`** `name` sends a task to sbt (and tests if it succeeds)
3.**`$`** `name arg*` performs a file command (and tests if it succeeds)
4.**`->`** `name` sends a task to sbt, but expects it to fail
5.**`-$`** `name arg*` performs a file command, but expects it to fail
File commands are:
- **`touch`** `path+` creates or updates the timestamp on the files
- **`delete`** `path+` deletes the files
- **`exists`** `path+` checks if the files exist
- **`mkdir`** `path+` creates dirs
- **`absent`** `path+` checks if the files don't exist
- **`newer`** `source target` checks if `source` is newer
- **`must-mirror`** `source target` checks if `source` is identical
- **`pause`** pauses until enter is pressed
- **`sleep`** `time` sleeps (in milliseconds)
- **`exec`** `command args*` runs the command in another process
- **`copy-file`** `fromPath toPath` copies the file
- **`copy`** `fromPath+ toDir` copies the paths to `toDir` preserving relative structure
- **`copy-flat`** `fromPath+ toDir` copies the paths to `toDir` flat
So my script will run `packageBin` task, and checks if a JAR file gets created. We'll cover more complex tests later.
### step 5: run the script
To run the scripts run the following from the sbt shell (in sbt/sbt):
```bash
> scripted project/something
```
**Note**: `scripted` runs all your tests.
This will copy your test build into a temporary dir, and executes the `test` script. If everything works out, you'd see `publishLocal` running, then:
```bash
[info] Tests selected:
[info] * project/something
[info] Running 1 / 1 (100.00%) scripted tests with LauncherBased(/Users/xxx/work/sbt/launch/target/sbt-launch.jar)
[info] Running project/something
[success] Total time: 12 s
```
Custom assertion
----------------
The file commands are great, but not nearly enough because none of them test the actual contents. An easy way to test the contents is to implement a custom task in your test build.
For my hello project, I'd like to check if the resulting jar prints out "hello". I can use `scala.sys.process.Process` to run the JAR. To express a failure, just throw an error. Here's `build.sbt`: