specks

specks enables a different way to check that your Ceylon code works.

Instead of writing traditional tests, you write specifications.

The main difference is the focus: specifications focus on behaviour and outcomes, while unit tests focus on interactions and, most of the time, implementation details.

For example, here's a very simple Specification written with specks:

testExecutor (`class SpecksTestExecutor`)
test
shared Specification simpleSpec() => Specification {
    expectations {
        expect(max { 1, 2, 3 }, equalTo(3))
    }
};

The testExecutor annotation can be added to a function, but also to a class or package… so you can avoid having to add it to every function.

For more information, visit Specks' GitHub page.

Packages
com.athaydes.specks

specks

com.athaydes.specks.assertion

Assertion functions to make writing specks Specifications more convenient.

com.athaydes.specks.matcher

Collection of matchers that can be used in conjunction with assertions.

Dependencies
ceylon.logging1.3.3
ceylon.random1.3.3
ceylon.test1.3.3.1

specks

specks enables a different way to check that your Ceylon code works.

Instead of writing traditional tests, you write specifications.

The main difference is the focus: specifications focus on behaviour and outcomes, while unit tests focus on interactions and, most of the time, implementation details.

For example, here's a very simple Specification written with specks:

testExecutor (`class SpecksTestExecutor`)
test
shared Specification simpleSpec() => Specification {
    expectations {
        expect(max { 1, 2, 3 }, equalTo(3))
    }
};

The testExecutor annotation can be added to a function, but also to a class or package… so you can avoid having to add it to every function.

A more complete specification would include a description, some examples, and a clear separation between what's being tested and what is being asserted.

test
shared Specification aGoodSpec() => Specification {
    feature {
        description = "The String.take() method returns at most n characters, for any given n >= 0";

        when(String sample, Integer n) => [sample.take(n), n];

        // just a few examples for brevity
        examples = {
            ["", 0],
            ["", 1],
            ["abc", 0],
            ["abc", 1],
            ["abc", 5],
            ["abc", 1k]
        };

        ({Character*} result, Integer n) => expect(result.size, toBe(atMost(n)))
    }
};

The toBe(..) function just returns the given matcher and is added only to improve readability

Notice that the when function runs with every example. If any example fails, the next ones would run anyway, so you would know exactly which cases pass and which fail.

A property-based testing approach can sometimes be a very good complement for manually-picked sample tests! For the previous example, this is certainly true.

Luckily, specks has great support for quickCheck-style testing:

test
shared Specification propertyBasedSpec() => Specification {
    forAll((String sample, Integer n)
        => expect(sample.take(n).size, toBe(atMost(n < 0 then 0 else n))))
};

This test will run the given function with 100 different, randomly-chosen values.

Aliases
BlockResultshared BlockResult=> {<[Anything[], String]->{SpecCaseResult*}()>*}

The result of running all cases of a Block of a Specification. The key in each entry of the stream represents a Tuple containing an example in the block and the block's description, whereas the value represents the lazily-obtained result of all assertions on that example.

SpecCaseFailureshared SpecCaseFailure=> String|Exception

The result of running a Specification case which fails or causes an error. A String represents a failure and describes the reason for the failure. An Exception means an unexpected error while running the Specification.

SpecCaseResultshared SpecCaseResult=> SpecCaseFailure|Success

The result of running a Specification case. A Specification case is defined as an assertion on the result given by a when function (for each example, where applicable).

SpecResultshared SpecResult=> BlockResult[]

Final result of running a Specification.

Successshared Success=> Null

The result of running a successful Specification case or a successful assertion

Annotations
unrollshared UnrollAnnotation unroll()

The unroll Annotation indicates that the results of a Specification should be split up into separate test results for each Specification case (or a combination of assertion/example), similar to ceylon.test parameters annotated tests.

UnrollAnnotationshared final UnrollAnnotation

Annotation class for unroll()

Values
successshared Success success

The single instance of type Success.

Functions
errorCheckshared Block errorCheck<Where = []>(Anything(*Where) when, {AssertionResult(Throwable?)+} assertions, String description = "", {Where*} examples = [], Integer maxFailuresAllowed = ...)
given Where satisfies Anything[]

The errorCheck block makes it possible to verify that an error condition produces the expected error or Throwable.

Parameters:
  • when

    The action being tested in this feature.

  • description = ""
  • examples = []

    Input examples.

    Each example will be passed to each assertion function in the order it is declared.

  • maxFailuresAllowed = 10

    Maximum number of failures to allow before stopping running more examples/assertions.

expectationsshared Block expectations({AssertionResult+} assertions, String description = "")

A Block that consists of a series of one or more expect() statements which verify the behaviour of a system.

Parameters:
  • assertions

    Assertions that verify the behaviour of a system.

  • description = ""

    Description of this group of expectations.

featureshared Block feature<out Where = [], in Result = Where>(Result(*Where) when, {AssertionResult(*Result)+} assertions, String description = "", {Where*} examples = [], Integer maxFailuresAllowed = ...)
given Where satisfies Anything[]
given Result satisfies Anything[]

A feature block allows the description of how a software functionality is expected to work.

Parameters:
  • when

    The action being tested in this feature.

  • assertions

    Assertions to verify the result of running the 'when' function.

  • description = ""

    Description of this feature.

  • examples = []

    Input examples.

    Each example will be passed to each assertion function in the order it is declared.

  • maxFailuresAllowed = 10

    Maximum number of failures to allow before stopping running more examples/assertions.

forAllshared Block forAll<Where>(AssertionResult(*Where) assertion, String description = "", Integer sampleCount = ..., [Anything()+]? generators = null, Integer maxFailuresAllowed = ...)
given Where satisfies Anything[]

Creates a Block for quick-check style (or property-based) testing.

Examples are generated automatically (or using the provided generators) and passed to the provided assertion function, which should assert that some invariant condition holds for all examples.

Parameters:
  • assertion

    Single assertion which should hold for all possible inputs of a given function

  • description = ""

    Description of this feature.

  • sampleCount = 100

    Number of sample inputs to run tests with

  • generators = null

    Input data generator functions. If not given, uses default generators.

  • maxFailuresAllowed = 10

    Maximum number of failures to allow before stopping running more examples/assertions.

propertyCheckshared Block propertyCheck<Result, Where>(Result(*Where) when, {AssertionResult(*Result)+} assertions, String description = "", Integer sampleCount = ..., [Anything()+]? generators = null, Integer maxFailuresAllowed = ...)
given Result satisfies Anything[]
given Where satisfies Anything[]

Creates a Block for more advanced quick-check style (or property-based) testing.

Examples are generated automatically (or using the provided generators) and passed to the provided when function, which then returns a Tuple whose elements are passed to the given assertions to verify that certain conditions hold for all examples that can be generated.

This Block is similar to a feature(), except that examples are automatically generated rather than hand-picked.

Parameters:
  • when

    The action being tested in this feature.

  • assertions

    Assertions to verify the result of running the 'when' function.

  • description = ""

    Description of this feature.

  • sampleCount = 100

    Number of sample inputs to run tests with

  • generators = null

    Input data generator functions. If not given, uses default generators.

  • maxFailuresAllowed = 10

    Maximum number of failures to allow before stopping running more examples/assertions.

randomBooleansshared {Boolean+} randomBooleans(Integer count = ..., Random random = ...)

Generates pseudo-random Boolean values.

Parameters:
  • count = 100

    the number of Booleans to generate - must be positive

  • random = defaultRandom

    Random instance to use for generating Booleans

Throws
  • Exception

    if count is smaller than 1

randomFloatsshared {Float+} randomFloats(Integer count = ..., Float lowerBound = ..., Float higherBound = ..., Random random = ...)

Generates pseudo-random Floats within the given bounds.

Parameters:
  • count = 100

    the number of Floats to generate - must be positive

  • lowerBound = -1.0M

    the lower bound, or lowest value that should be generated

  • higherBound = 1.0M

    the higher bound, or maximum value that should be generated

  • random = defaultRandom

    Random instance to use for generating Floats

Throws
  • Exception

    if count is smaller than 1 or lowerBound > higherBound

randomIntegersshared {Integer+} randomIntegers(Integer count = ..., Integer lowerBound = ..., Integer higherBound = ..., Random random = ...)

Generates pseudo-random integers within the given bounds.

Parameters:
  • count = 100

    the number of integers to generate - must be positive

  • lowerBound = -1M

    the lower bound, or lowest value that should be generated

  • higherBound = 1M

    the higher bound, or maximum value that should be generated

  • random = defaultRandom

    Random instance to use for generating Integers

Throws
  • Exception

    if count is smaller than 1 or lowerBound > higherBound

randomStringsshared {String+} randomStrings(Integer count = ..., Integer shortest = 0, Integer longest = ..., [Character+] allowedCharacters = ..., Random random = ...)

Generates pseudo-random Strings.

Parameters:
  • count = 100

    the number of Strings to generate - must be positive

  • shortest = 0

    the lower bound for the String size

  • longest = 100

    the higher bound for the String size

  • allowedCharacters = '\{#20}'..'\{#7E}'

    Allowed characters for the returned Strings

  • random = defaultRandom

    Random instance to use for generating Strings

Throws
  • Exception

    if count is smaller than 1 or longest < shortest

rangeOfIntegersshared {Integer+} rangeOfIntegers(Integer count = ..., Integer lowerBound = ..., Integer higherBound = ...)

Generates a range of integers within the given bounds.

The integers are not random and depend only on the values of count and the bounds. The generated values are appropriate for tests - an attempt is made to include boundary values and uniformly distribute the values.

Parameters:
  • count = 100

    the number of integers to generate - must be positive

  • lowerBound = -1M

    the lower bound, or lowest value that should be generated

  • higherBound = 1M

    the higher bound, or maximum value that should be generated

Throws
  • Exception

    if count is smaller than 1 or lowerBound > higherBound

runshared void run()

Run the module com.athaydes.specks.

Interfaces
Blockshared Block

Most generic kind of block which forms a Specification.

specks provides many different kinds of Blocks that can be created with functions such as feature(), expectations(), errorCheck() and, to enable property-based tests, quickcheck style, forAll(), propertyCheck().

Classes
Specificationshared Specification

Top-level representation of a Specification in specks.

SpecksTestExecutorshared SpecksTestExecutor

specks test executor. To run your Specifications using Ceylon's test framework, annotate your top-level functions, classes, packages or your whole module with the testExecutor annotation.

For example, to annotate a single test:

testExecutor(`class SpecksTestExecutor`)
test shared Specification mySpeck() => Specification {
    ...
};