3 minute read

The intro

It’s Saturday and I don’t want to do real work, so let’s code.

Ever since the new year, I’ve been meaning to get into better TDD/testing approaches. I’d previously heard about mutation tests and property-based testing but I didn’t have a project to try those on.

Requirement: stand up a relatively simple and straightforward application, apply tests, note findings, repeat.

easy, right?

The start

I loaded up IntelliJ and decided to initialize a Spring Boot application with some data that I had handy. I have been tracking my basic physical workouts in Google Keep since the start of the year, so I have about 10 weeks worth of data to use.

Let’s call this - the FitnessTrackerApplication. The expectation is that it reads from an in-memory H2 database and spits out whatever data I want to find, based on my filtering. This application won’t have any UI yet, because I just want to focus on the data and my testing.

I started commenting my pom files, to ensure that I always know what dependencies I’m bringing in and why.

<dependencies>
    <!-- For production-level utilities -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <!-- For REST endpoint web stuff -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- database -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>

    <!-- TDD 4ever -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <!-- annotations -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
        <version>1.5.10.RELEASE</version>
    </dependency>
</dependencies>

Straightforward, straightforward.

Now on to the data.

-- schema.sql, to be loaded in on startup
CREATE TABLE FITNESS_LOG (
  LOG_DATE  DATE PRIMARY KEY,
  PUSHUPS   INT,
  PULLUPS   INT,
  CRUNCHES  INT,
  SUPERMANS INT
);

-- data.sql, to be inserted on startup
INSERT INTO FITNESS_LOG (LOG_DATE, PUSHUPS, PULLUPS, CRUNCHES, SUPERMANS) VALUES
  ('2017-01-01', 40, 9, 0, 0),
  ('2017-01-07', 77, 23, 0, 0),
  ('2017-01-14', 200, 12, 0, 0),
  ('2017-01-21', 200, 35, 0, 0),
  ('2017-01-28', 200, 86, 0, 0),
  ('2017-02-04', 200, 100, 0, 0),
  ('2017-02-11', 200, 110, 0, 0),
  ('2017-02-18', 200, 116, 15, 10),
  ('2017-02-25', 200, 104, 15, 10),
  ('2017-03-05', 210, 110, 25, 0),
  ('2017-03-12', 200, 100, 42, 11);

Great, still not very interesting yet.

I’ll go ahead and start creating my first POJO, the FitnessLog class. Afterwards, I’ll throw in a JPA repository. Next, a controller endpoint (just to get the basic gist running). Finally, we run and I get the following JSON response from my endpoint (I’m using Insomnia instead of Postman, because cool).

<URL>:8080/api/fitness-logs

cry

I’ve been duped! Rats! I’ve got nothing!

The debugging

Note: one really important thing to have is an easy way to debug incoming requests. In Spring Boot, this is as easy as adding the following bean to your main application class and the following property in your application.yml/properties.

logging.level.org.springframework.web=DEBUG
@SpringBootApplication
public class FitnessTrackerApplication {
    public static void main(String[] args) {
        SpringApplication.run(FitnessTrackerApplication.class, args);
    }

    @Bean
    public CommonsRequestLoggingFilter logFilter() {
        CommonsRequestLoggingFilter filter
                = new CommonsRequestLoggingFilter();
        filter.setIncludeQueryString(true);
        filter.setIncludePayload(true);
        filter.setMaxPayloadLength(10000);
        filter.setIncludeHeaders(false);
        filter.setAfterMessagePrefix("REQUEST DATA : ");
        return filter;
    }
}

I promise I’ll do the TDD soon. Just want to get the main structure of the app up and then we’ll begin.

Problem #1

For some reason, not able to see any data retrieved. The logs say that the db scripts get executed.

Problem #2

My data continues to be wiped. I booted up the h2 console by adding the following lines to my application.properties:

# To stop default behaviour of wiping out my sql schema
spring.jpa.hibernate.ddl-auto=validate

# Enabling H2 Console
spring.h2.console.enabled=true

bad-console

Solution #2

A bunch of debugging later, and I realized my h2-console was pointed to the wrong instance of the h2 database. It should be pointing to jdbc:h2:mem:testdb in the JDBC URL location. There, I could see my tables.

good-console

By adding the validate option as well, I found another issue with my data:

Problem #3

Schema-validation: wrong column type encountered in column [log_date] in table [fitness_log]; found [date (Types#DATE)], but expecting [timestamp (Types#TIMESTAMP)

Solution #3

It’s crazy, but the Date object that I used in my FitnessLog class was from the java.util library and by changing it to the java.sql library, all was good.

The pleading

Dear glob, please just work. -le me, after another hour of grinding

Sweet beautiful JSON.

joy

I’m done with this for today, but I’ll do some necessary cleanup.

Code can be found here! Tagged for part-i.

P.S. I technically TDD’d because I have 1 test. lol.