Using Kotlin in a Serverless Architecture with AWS Lambda — Part 5: Testing Your Code

Using specification frameworks to test your code in a Bacon-Driven Development fashion

Juan Urrego
Tech@Travelstart
5 min readFeb 3, 2019

--

Photo by Casey DeViese on Unsplash

So far I have covered all the basics to set up, build and deploy your Serverless + Kotlin project using AWS Lambda as our FaaS platform. So I bet the next question that you have in mind is: How can I test it? In this article, I’ll present tools and methods to perform automated tests using a specification framework for Kotlin and, luckily, you will have a fully tested product at the end.

Index

  1. Setting up the project
  2. Setting up your local development environment
  3. Designing and implementing a Multi-Tier Lambda App
  4. A Multi-layer core for your function: A request-dispatcher and micro HTTP router implementation
  5. Testing your code
  6. Integrating a RDBMS to your project (coming soon)
  7. Authentication & Authorisation using Amazon Cognito (coming soon)
  8. Creating an end-to-end RESTFul service (coming soon)

Beyond Unit Tests

Something that I’ve learned during my professional experience as a software engineer is that tests are not just to verify that 2 + 2 = 4. They’re also a valuable tool to document and understand how your code should behave and respond under certain conditions. That’s why there are different flavours to them: Smoke Tests, Behavioural Tests, Regression Tests, Usability Tests, etc.

In general terms, tests are executable specifications of your system that can be encompassed into a Specification Framework.

A Specification Framework is a tool or method that helps us define an explicit, concise, and unambiguous test plan for our system

In the case of Kotlin, some authors have called this way of testing Bacon Driven Development, thanks to its most famous specification framework: Spek. Note: Spek in Dutch means bacon (now you understand the pun).

Developing Tests with Spek

One of the first things that we need to understand from Spek, is that it’s just a specification framework. For that reason, we can use any assertion library such as JUnit, Kotlin Test, Kluent, HamKrest, Expekt, etc. In this article, I’m going to use Spek + JUnit and Mockito as our Mock framework. Note: The use of JUnit is to avoid introducing too many new frameworks/libraries to the reader. However, I recommend to use KotlinTest as your assertion library for your future projects. Stephen Samuel has written some good articles about KotlinTest such as Data Driven Testing With Kotlin and Kotlin Test Pro Tips.

Gradle Dependencies

The current stable version for Spek is the 1.x version with a 2.x version in development. I’m going to use version 1.1.5, which is the latest stable and supported one. Please include the next lines of code into your gradle file:

// Include the JUnit Dependency to import the JUnit plugin
buildscript {
...
dependencies {
...
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0'
}
}
...
apply plugin: 'org.junit.platform.gradle.plugin'
// Includes Spek as part the JUnit Engines
junitPlatform {
filters {
engines {
include 'spek'
}
}
}
// Downloads Spek
repositories {
...
maven { url "http://dl.bintray.com/jetbrains/spek" }
}
dependencies {
...
// Compiles JUnit, Mockito Core and Mockito-Kotlin
testCompile 'org.mockito:mockito-core:2.+'
testCompile 'com.nhaarman:mockito-kotlin:1.5+'
testCompile 'org.jetbrains.spek:spek-api:1.1.5'
testCompile 'org.junit.platform:junit-platform-runner:1.0.0'
// Includes Spek engine
testRuntime 'org.jetbrains.spek:spek-junit-platform-engine:1.1.5'
}

Note: Don’t try to include JUnit4, you will face multiple problems with your IDE. The official documentation states: “As mentioned in the IDE Support section, the IDEA plugin won’t work if you’re using the JUnit 4 runner”.

Designing Your Specification

Some of the most beautiful and useful concepts that Behavioural Driven Development (BDD) has introduced to the tech community are the Test Narrative and the Acceptance Criteria/Scenarios. Authors like Bob C. Martin defines the last one as the Given-When-Then convention, where:

  • Given a specific context
  • When some action or event is being triggered
  • Then an expected outcome should be obtained

Some BDD frameworks such as JBehave, RSpec, Mocha, Jasmine, Cucumber, among others, embrace the use of this template. Spek is not an exception to this rule. The main difference is that it doesn’t force you to use a concrete assertion framework or additional behavioural files (e.g Cucumber or JBehave).

Spek embraces the use of two different styles:

  • Given → On → It : In this case we define a context (given), specific action (on) and the test itself (it).
  • Describe → It: This second style defines a context (describe) and the actual test (it).

Additionally, Spek provides the concept of fixtures. Each one can run arbitrary code during different moments of the test life cycle. Some of those fixtures are:

  • beforeGroup
  • beforeEachTest
  • afterEachTest
  • afterGroup

Note: For further details visit the official Spek documentation website.

Testing Our Handler

Now that we already understand the basics, let’s drop some code! For our specific context, the first component that we should always test is the ApplicationHandler. Remember that handlers are the main point of entry to our Lambda Functions. Thus, if by chance we raise errors at this level, it is likely that our complete function will fail.

As I explained in the previous article, A Multi-layer core for your function: A request-dispatcher and micro HTTP router implementation, it is possible to implement a Client-Dispatcher-Server to reuse the same Handler for multiple functions. So maybe we should test that given an event, we can route to a specific function defined in our routes.yml file and return the correct HTTP Status code.

To do that, let’s create a file in src > test > kotlin > com.myblockbuster > TestHandler like this:

The previous TestHandler class will execute 3 different tests given an input event under different actions/conditions. Let’s start with the class declaration. We are extending from a Spek class and using its own DSL via lambda functions (thanks to type-safe builders).

Furthermore, inside the first given block, we’re using the beforeEachTest fixture to define an environment for our future tests. To mock the Lambda Context object and the dispatcher behaviour we can always use Mockito.

As you can observe, I decided to use the given → on → it style, which in my opinion is the closest one to the given → when → then convention. For this particular case, we want to test the routing correctness through the HTTP status codes. So if an input path exists it should return 204 for an empty payload and 200 for a correctly pay-loaded response. On the other hand, if an input path doesn't exist we should return a 404 code.

Finally, to run our tests in your IDE try to right click > Run Tests on the TestHandler.kt file or execute the command gradle test in your console. You should see something like this:

Execution of Spek Tests in IntelliJ

SOURCE CODE

If you want to see the complete example, the source code is available at this Github repo.

Final Thoughts

Specification frameworks are a nice way to complement, improve, and make our unit or integration tests more readable. In an industry where people don’t see a benefit to the documentation, using a specification framework is a nice way to describe the inputs, context and outputs of your code using something that developers understand… you guessed it! code.

See you soon and don’t forget to clap & subscribe.

Part 6: Integrating a RDBMS to your project (COMING SOON)

--

--