Skip to main content

Programming Foundations - Lotto Session #3 (Kotlin, Spring, & Spock)



In this session, we construct the beginnings of a Lottery application that will utilize the Lotto model we introduced in Session #1 and later refactored (as Kotlin) in Session #2.  If you missed those sessions, refer to this same blog site to review that content.


One new technology introduced in this session will be Spring.  The best way to think of Spring is as a programming and configuration model used to assist with the construction of applications.  Its primary contribution is to provide architectural and design foundations.

Specifically, we will be utilizing what is called Spring Boot, which provides convention over configuration and allows you to get started with minimal setup.  What this translates to, is minimal configuration needed to use the Spring framework features.

A side note: Spring Framework 5.x and Spring Boot 2.x have first class support for Kotlin, which is another good reason to give this language a serious look!
Application Entry Point

We start with identifying our Spring Boot application using an annotated class.

@SpringBootApplication
class SessionsApplication

     fun main(args: Array<String>) {
          SpringApplication.run(SessionsApplication::class.java, *args)
     }

In Kotlin, classes, functions and methods are public by default, so no need to specify this in our case. Also, functions that return nothing, do not need to specify a ‘void’ keyword in Kotlin.  Again, this is the simplicity that Kotlin provides, which reduces your overall source footprint.

We now need to construct our lottery loader component that will do the actual work of loading up some lottery picks.  Since we are using Spring, we can easily setup a web service endpoint that will perform our work.  One way is to use Spring’s @RestController and @RestMapping annotations.

Using these two annotations allows us to perform a GET command targeting the REST service endpoint from a browser (or by using a test driver).  We also need to validate our picks to ensure we don’t have an issue, which would result in invalid picks being loaded.  By using a try/catch block we detect issues that may occur, and respond accordingly back to the service caller.



Now that the lotto load logic is written and compiled, the application can be started by running our SessionsApplication class. Remember this class was designated as our SpringBootApplication using the Spring Boot annotation.

When run, the LottoLoader controller is initialized, and it will become available to handle GET requests as specified.



Using a browser to test our service, we connect to the Tomcat port (in this case 8080) that was made available by the Spring Boot application upon startup.  And, we can see that the drawings were loaded successfully as expected through a message back the browser client.

Browser Snippet

This example is somewhat simplistic as we haven’t involved any other integration points to resources such as files or databases.  However, the point here is that with a small amount of Spring and Kotlin, we now have a REST-based web service interface we can use to do many more useful activities.  This shows the power of Spring and Spring Boot and how it can work seamlessly with our existing Lotto model written in Kotlin.

Refactoring Option

Remember touching on best-practices for software development in session 1 and 2? We now can apply the “single responsibility” pattern to our application.  In the first version of the controller, we have the logic for the web service directly included in the class.  We can migrate & decouple that logic so if we were to use a non web service approach, we can simply refer to our logic without impacting the web service implementation.  For example, a requirement comes in to create a command line interface that needs to obtain and display the lottery drawings.

In our refactoring, we can now leave the web service call handling to the controller. Think single responsibility here.  A Spring component/service will be introduced to simply retrieve the lotto drawings from whatever source (file, database, etc.) we decide in the future.   This approach keeps the code cleaner for better comprehension, reuse, and testing.  Let’s explore further…

Refactored Controller



Introduction of Service

Taking the decoupling a step further, the actual construction of the PowerDrawing and its validation is decoupled from the service itself.  This will allow for adjustments to the service in the future where different types of drawings are retrieved from whatever data source (e.g. file system, database, or an in-memory cache).



Lotto Data

In this case, we are simulating the PowerDrawing data using randomized numbers that makeup the core picks (ensuring no duplicates within picks) and the power pick itself.


Unit Test Coverage

First, we want to test that when we invoke our logic we get accurate & positive results as expected. Second, we need to cover the “rainy day” scenarios where we don’t have a valid response to ensure our exception handling works as expected.  How do we do this?  

From a unit testing coverage perspective, for this session, we will ensure that our Service and Controller have some level of test coverage.  If we have separate tests covering the logic of each, we are testing that our classes have the single responsibility patterns applied and behave as expected.   This way, when a unit test is written it is just testing a specific set of functionality and not running the entire application to do so. Time to test what we have constructed!

Testing the Lotto Web Service Controller

This is where we can utilize our new friend Spring along with our old friend Spock to help us out with something that may not seem easy to test at first glance.  There are some really handy Spring utilities that assist with “mocking” out various components to ensure we can construct valid unit tests. Want to learn more about mocking? Checkout some great sites related to Spring and Spock testing:


The following classes will be utilized to mock out the scaffolding that is provided by Spring at runtime, which hosts our web service using Spring MVC.  
  • org.springframework.test.web.servlet.MockMvc
  • org.springframework.test.web.servlet.request.MockMvcRequestBuilders
In unit test coverage, we aren’t testing that the Spring plumbing is up and running, that would lean more towards an integration type of test.  We just want to validate logic we’ve written as part of the Controller, and we do this by mocking out the servlet and server portions using the Spring servlet mock classes.



To perform this mocking, we use the standaloneSetup operation that will be initialized with our implementation of the LottoController.  Once we have this mockMvc reference, we use in in our test operations to perform various activities.  In this case, we perform an HTTP GET call to the mock that will invoke our LottoController load operation by matching the URL and HTTP method provided. Once we get a response, we can check for expected status, return message, etc.

Although not included in this example, it is quite possible that since we will be testing our LottoService separately, the Controller test could further mock the call to the LottoService.  The scope of the test in this case is the Controller behavior. When unit testing, it is good practice to isolate what you are testing otherwise your test logic becomes extremely brittle and difficult to refactor as your actual application logic changes.

Testing LottoService

Testing the service is quite straightforward as we don’t need to worry about calling out using a URL, it is just a direct call to the getDrawings() operation exposed by the LottoService.

Valid Test




Invalid Test



What does all this effort do for our application?  We are able to get great test coverage for our model and service classes, and this translates to higher quality deliverables over time.  When logic requires change (and it most likely will) the tests will assist with identifying areas that are impacted by change.



As always, checkout the full source for yourself.  I hope you enjoyed seeing Kotlin in action with Spring and Spock!

References

Spring / Spring Boot
Kotlin Spring Starter
Kotlin Support In Spring

Mocking

Comments

  1. Updated negative test coverage for the loader, as such, the actual test code will differ slightly from the examples above. Will get those updated in the blog shortly.

    ReplyDelete

Post a Comment