Kotlin Specification Framework
Switch branches/tags
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
dist
gradle
kspec-console-runner
kspec-core
kspec-engine
kspec-junit-runner
kspec-launcher
samples
.gitignore
.travis.yml
LICENSE.md
README.md
build.gradle
gradle.properties
gradlew
gradlew.bat
settings.gradle

README.md

(NO LONGER MAINTANED) KSpec -> Spek.

KSpec

Bintray Build Status codecov.io

Specifications for Kotlin.

Basic Structure

class TheMostAmazingAnimalSpec: KSpec() {
    override fun spec() {
        describe("the most amazing animal in the universe") {
            val animal = GetMostAmazingAnimal()
            it("should be a panda") {
                assertThat(animal.type, equalTo("panda"))
            }
            
            context("not a panda") {
                it("nope, not going to accept it") {
                    assertThat({
                        assertThat(animal.type, not(equalTo("panda")))
                    }, thrown(EndOfTheWorldException::class))
                }
            }
        }
    }
}

Context

KSpec is heavily inspired by RSpec, Context is synonymous to RSpec's scopes.

Example

The test method in JUnit and created using it.

ExampleGroup

Groups similar examples together (they might be testing the same Subject - more on this later) and is created by using describe or context. Be cautious in placing logic code in them as they are eagerly evaluated

Fixtures

KSpec provides before, beforeEach, afterEach and after callbacks for each context.

Subject

Just like RSpec, KSpec also support subjects.

class TheMostAmazingAnimalSpec: KSpec() {
    override fun spec() {
        describe("the most amazing animal in the universe") {
            subject {
                return@subject GetMostAmazingAnimal();
            }
            
            it("should be a panda") {
                assertThat(subject.type, equalTo("panda"))
            }
            
            context("not a panda") {
                it("nope, not going to accept it") {
                    assertThat({
                        assertThat(subject.type, not(equalTo("panda")))
                    }, thrown(EndOfTheWorldException::class))
                }
            }
        }
    }
}

Shared Examples

Sometimes it's convenient to reuse examples - like testing a subclass.

class CalculatorSpec: KSpec() {
    override fun spec() {
        describe(Calculator::class) {
            itBehavesLike(calculator())
        }
    }
    
    companion object {
        fun calculator() = sharedExample<Calculator> {
            describe("add") {
                it("1 + 1 = 2") {
                    assertThat(subject.add(1, 1), equalTo(2))
                }
            }
            ...
        }
    }
}

class AdvancedCalculatorSpec: KSpec() {
    override fun spec() {
        describe(AdvancedCalculator::class) {
            itBehavesLike(CalculatorSpec.calculator())
        }
    }
}

Pending

You can write specs in advance, KSpec will ignore them during execution.

class SomeSpec: KSpec() {
    override fun spec() {
        xdescribe("a pending group") {
            it("won't be executed") { }
        }

        xcontext("another pending group", "some reason")

        xit("a pending example") { }
    }
}

Focused

KSpec supports focusing execution only on several contexts. Use fdescribe and fcontext to create a focused group, and fit to create a focused example. KSpec will only run focused contexts if there are any, othewise it will run everything.

Tagging

TODO

Filters

This allows to control which contexts to run. It can be configured per spec (by overriding configure) or by using Shared Configurations.

class SomeSpec: KSpec() {
    override fun configure(config: KSpecConfig) {
       // config.filter.<filter> = tags
    }
}

include

Only include contexts having at least one of the tags specified.

exclude

Exclude any contexts having at least one of the tags specified.

matching

Similar to the include filter, the only difference is that if there is no match run everything.

Shared Configurations

Declare shared configurations by extending Configuration and apply it to a spec via @Configurations.

class SharedConfiguration: Configuration {
    override fun apply(config: KSpecConfig) {
        ...
    }
}

class AnotherConfiguration: Configuration {
    override fun apply(config: KSpecConfig) {
        ...
    }
}

// use it
@Configurations(
    SharedConfiguration::class,
    AnotherConfiguration::class
)
class SomeSpec: KSpec() {
    ...
}

Usage

Console Runner

TODO

Gradle

Currently you need to use a JUnit4 Runner to be able to run specs with gradle. Make sure to annotate your test classes with @RunWith(JUnitKSpecRunner::class).

repositories {
    jcenter()
}

dependencies {
    testCompile "io.polymorphicpanda.kspec:kspec-core:<kspec-version>"
    testCompile "io.polymorphicpanda.kspec:kspec-junit-runner:<kspec-version>"
}

Development version

Gradle

repositories {
    maven {
        url "http://oss.jfrog.org/artifactory/oss-snapshot-local/"
    }
}