BDD Test Framework with Kotlin

Today I'll present what I've done for Spek project. Spek is the BDD test framework for Kotlin

Problem statement

I decided to make Spek test framework to be supported by existing java testing tools, starting from a test runner with IntelliJ IDEA to supporting Spek test runs under build scripts, TeamCity, code coverage and so on. This list looks too big to describe it one blog post, don't it? Ok, the idea behind is to re-use existing java test runner.

There are two major testing frameworks for Java. First and the oldest one is JUnit. The second one is TestNG

From the start I figured out how to extend JUnit in order to change the way it runs tests. Unfortunately, I found no easy way on how to implement similar things with TestNG. (Personally, I prefer TestNG to JUnit :)

Tesing Framework Details

Let's start with small introduction to BDD-like testing frameworks. How should look an ideal BDD test framework use case? At least it should not contain extra language-specific code that makes it harder to read. Hadi created an awesome DSL for that in Kotlin. This is how BDD test may look:

Abstracting DSL

DSL API

First implementation of Spek DSL was running all closures in-place. That was the thing I decided to change. For JUnit test runner integration I was needed to have more control over tests code evaluation.

As side task I split Spek DSL definitions from Spek DSL implementations. Finally, I migrated Spek DSL into the following API definition:

The only thing that is missing in the code above is the implementation of Spek interface. Meanwhile, the code above defines the rest of test API.

DSL Model

I going to have a number of interfaces to represents test execution stages:

Next is to provide implementation of methods given, on, it. Let's start with given and on:

The trick here is that execution of onExpression function is moved inside anonymous class that is created by the method. So instead of executing all functions, it records them. Another thing is that onExpression is an extension method for On class, so call looks like member execution, i.e. o.onExpression(). Implementation of On and It is mostly same-looking. Let's move to JUnit test runner.

JUnit

Integration with JUnit is simple. One need to mark test class with @RunWith annotation and provide a test runner class with a constructor from Class that extends Runner class.

To hide such details, I come up with tests base class. This class implements Spek interface and provides JUnit specific setup

With use of the base class for Spek tests for JUnit looks like:

You may notice here double {{ and }}. Those are used intentionally, because test model is constructed in class constructor with help of given method implementation. Then the model is used from JSpec<T> class to implement Runner class from JUnit

Conclusions

I made many changes to Spek BDD testing framework to support tests execution both from Console and from JUnit. Thanks Hadi for accepting my pull request for Spek.

Now you could see your test runs with IDEA's JUnit runner!

For more details, see source code of Spek here.

comments powered by Disqus