Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/kkrull/javaspec
Spec-style testing for Java
https://github.com/kkrull/javaspec
java junit lambda spec specifications test testing
Last synced: 5 days ago
JSON representation
Spec-style testing for Java
- Host: GitHub
- URL: https://github.com/kkrull/javaspec
- Owner: kkrull
- License: mit
- Created: 2014-07-25T02:23:57.000Z (over 10 years ago)
- Default Branch: main
- Last Pushed: 2023-03-07T20:29:44.000Z (over 1 year ago)
- Last Synced: 2024-02-17T15:53:04.092Z (9 months ago)
- Topics: java, junit, lambda, spec, specifications, test, testing
- Language: Java
- Homepage: https://javaspec.info
- Size: 1.69 MB
- Stars: 8
- Watchers: 2
- Forks: 1
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# JavaSpec
JavaSpec 2 is a library for the Java Virtual Machine that lets you use lambdas
to write specifications (unit tests) that run on the JUnit Platform.
Specifications run anywhere JUnit 5 runs: Gradle, JUnit Platform Console, or
your favorite IDE. It does the same thing you can do with JUnit 5, but with a
syntax that is more descriptive–and more concise–than its JUnit counterpart.JavaSpec 2 should work just about anywhere JUnit 5 works. All you have to do is
add a compile dependency for the API (providing the new spec syntax) and a
runtime dependency for a JUnit Test Engine that knows how to turn specifications
into JUnit tests._TL;DR - it's kind of like the syntax from [Jest][jest], [Mocha][mocha], and
[Jasmine][jasmine], but for Java._**Note that this documentation is for the new version of JavaSpec**. It uses a
different syntax than [JavaSpec 1.x][javaspec-1x].- [What does JavaSpec do?](#what-does-javaspec-do)
- [Getting Started](#getting-started)
- [Add dependencies](#add-dependencies)
- [Write Specs](#write-specs)
- [Run specs with Gradle](#run-specs-with-gradle)
- [Run specs in your IDE](#run-specs-in-your-ide)
- [Run specs with JUnit Platform Console](#run-specs-with-junit-platform-console)
- [More helpful syntax](#more-helpful-syntax)
- [Support](#support)
- [Known Issues](#known-issues)![Build Status](https://github.com/kkrull/javaspec/actions/workflows/verify.yml/badge.svg?branch=main)
[jasmine]: https://jasmine.github.io/
[javaspec-1x]: http://javaspec.info
[jest]: https://jestjs.io/
[mocha]: https://mochajs.org/## What does JavaSpec do?
JavaSpec helps you take a JUnit test that looks like this...
```java
class GreeterTest {
@Nested
@DisplayName("#greet")
class greet {
@Test
@DisplayName("greets the world, given no name")
void givenNoNameGreetsTheWorld() {
Greeter subject = new Greeter();
assertEquals("Hello world!", subject.greet());
}@Test
@DisplayName("greets a person by name, given a name")
void givenANameGreetsThePersonByName() {
Greeter subject = new Greeter();
assertEquals("Hello Adventurer!", subject.greet("Adventurer"));
}
}
}
```...and declare it with lambdas instead:
```java
@Testable
public class GreeterSpecs implements SpecClass {
public void declareSpecs(JavaSpec javaspec) {
javaspec.describe(Greeter.class, () -> {
javaspec.describe("#greet", () -> {
javaspec.it("greets the world, given no name", () -> {
Greeter subject = new Greeter();
assertEquals("Hello world!", subject.greet());
});javaspec.it("greets a person by name, given a name", () -> {
Greeter subject = new Greeter();
assertEquals("Hello Adventurer!", subject.greet("Adventurer"));
});
});
});
}
}
```This results in test output that looks like this:
```text
Greeter#greet
✔ greets the world, given no name
✔ greets a person by name, given a name
```Using this syntax, you can describe behavior with plain language without having
to add extra decorators or name tests twice (one machine-readable method name
and one human readable `@DisplayName`).If you're into testing, like being descriptive, and don't mind lambdas: this
might be the testing library for you.## Getting Started
### Add dependencies
To start using JavaSpec, add the following dependencies:
1. `testImplementation 'info.javaspec:javaspec-api'`: the syntax you need to
declare specs. This needs to be on the classpath you use for compiling test
sources and on the one you use when running tests.
1. `testRuntimeOnly 'info.javaspec:javaspec-engine'`: the `TestEngine` that runs
specs. This only needs to be on the classpath you use at runtime when
running tests.
1. some kind of library for assertions. For example:
`testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'`In Gradle, that means adding the following to your `build.gradle` file:
```groovy
//build.gradle
dependencies {
//Add these dependencies for JavaSpec
testImplementation 'info.javaspec:javaspec-api:'
testRuntimeOnly 'info.javaspec:javaspec-engine:'//Add an assertion library (JUnit 5's assertions shown here)
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
}
```### Write Specs
Start writing specs with JavaSpec the same way you would with JUnit: by making a
new class. It is often helpful for the name of that class to end in something
like `Specs`, but JavaSpec does not require following any particular convention.Once you have your new spec class:
1. Implement `SpecClass` (`info.javaspec:javaspec-api`) and
`#declareSpecs(JavaSpec)`.
2. Inside `declareSpecs`, call `JavaSpec#describe` with:
1. some description of what you are testing (or the class itself)
2. a lambda to hold all the specifications for what you're describing
3. Inside the `describe` lambda, call `JavaSpec#it` with:
1. some description of the expected behavior
2. a lambda with [Arrange Act Assert][c2wiki-arrange-act-assert] in it, like
in any other testPut it all together, and a basic spec class looks something like this:
```java
import info.javaspec.api.JavaSpec;
import info.javaspec.api.SpecClass;public class GreeterSpecs implements SpecClass {
public void declareSpecs(JavaSpec javaspec) {
javaspec.describe(Greeter.class, () -> {
javaspec.describe("#greet", () -> {
javaspec.it("greets the world, given no name", () -> {
Greeter subject = new Greeter();
assertEquals("Hello world!", subject.greet());
});
});
});
}
}
```[c2wiki-arrange-act-assert]: http://wiki.c2.com/?ArrangeActAssert
### Run specs with Gradle
Once you have the right dependencies, you need a way to run specs on the JUnit
Platform. This section describes how to do that in a Gradle project.As with regular JUnit tests, you still need to add this to your `build.gradle`:
```groovy
//build.gradle
test {
useJUnitPlatform()
}
```Then it's `./gradlew test` to run specs, like usual.
For extra-pretty console output, try adding the [Gradle Test Logger
Plugin][github-gradle-test-logger-plugin] with the `mocha` theme.[github-gradle-test-logger-plugin]: https://github.com/radarsh/gradle-test-logger-plugin
### Run specs in your IDE
If you have an IDE that can already run JUnit 5 tests, there's a good chance
that it can also run JavaSpec by following these steps:1. Make sure you have added the dependencies listed in
[Add Dependencies](#add-dependencies).
2. Add the JUnit Platform Commons dependency:
`testImplementation 'org.junit.platform:junit-platform-commons:'`
3. Add `@Testable` to each `SpecClass` that contains specifications, as a hint
to your IDE that this class contains some sort of tests that run on a
`TestEngine`.This is usually enough for your IDE to indicate that it can run tests in a
class, once it has had time to download any new dependencies and index your
sources.For example:
```java
import org.junit.platform.commons.annotation.Testable;@Testable //Add this IDE hint
public class GreeterSpecs implements SpecClass {
public void declareSpecs(JavaSpec javaspec) {
javaspec.describe(Greeter.class, () -> {
...
});
}
}
```### Run specs with JUnit Platform Console
Since this is just another `TestEngine` for the JUnit Platform, you can also run
specs on the [JUnit Platform Console][junit-console-launcher] as seen in this
shell snippet:```shell
junit_console_jar='junit-platform-console-standalone-1.8.1.jar'
java -jar "$junit_console_jar" \
--classpath=info.javaspec.javaspec-api-0.0.1.jar \
--classpath= \
--classpath= \
--classpath=info.javaspec.javaspec-engine-0.0.1.jar \
--include-engine=javaspec-engine \
...
```Specifically, this means running passing the following arguments to JUnit
Platform Console, on top of whichever options you are already using:- `--classpath` for `javaspec-api` and `javaspec-engine`
- `--include-engine=javaspec-engine`[junit-console-launcher]: https://junit.org/junit5/docs/current/user-guide/#running-tests-console-launcher
### More helpful syntax
The JavaSpec API supports a few more things that developers often need to do
while testing:- `JavaSpec#pending`: Stub in a pending / todo item reminding you to test
something later. JUnit Platform skips the resulting test.
- `JavaSpec#skip`: Skip running a spec that already has a defined procedure.
This can be useful for allowing a spec to be _temporarily_ disabled while you
fix something else.The API also has a variety of ways to help you organize your specs:
- `JavaSpec#describe` is used most often to define the class and methods being
tested, but it is really just a general-purpose container with no special
behavior of its own.
- `JavaSpec#context` can be useful for defining any circumstances under which
some specifications apply. It's not implemented any differently from
`#describe`, so use `#context` if you feel like it reads better.
- `JavaSpec#given` is like the other containers, except that it adds the word
"given" before your description. For example
`javaspec.given("a name", () -> ...)`
results in a container called `given a name`.Note that these containers exist simply to help you be as descriptive and
organized as you need to be. Try to use them judiciously to enhance human
readability.## Support
Feel free to file an [Issue on Github][github-javaspec-issues] if you have any
questions about using JavaSpec, or if something is not working the way you
expected.[github-javaspec-issues]: https://github.com/kkrull/javaspec/issues
### Known Issues
- There is not an equivalent of `@BeforeEach` and `@AfterEach` yet, for defining
shared setup and teardown around a series of related specs.
- Running specs in Gradle causes specs to be reported under `default-package`
and `UnknownClass` instead of their actual package and class names. This
applies to HTML test reports in `build/reports/tests/test`.
- Running specs in Gradle with the [Gradle Test Logger
Plugin][github-gradle-test-logger-plugin] causes the name of the spec class to
be printed _after_ all the specs in the class have run, instead of _before_
it.