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.
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 using 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.
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:
Note: At time of writing, 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 Behavioral 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 behavioral 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:
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 behavior 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 payload. 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
If you want to see the complete example, the source code is available at this Github repo.
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.
Originally posted at Medium