Lesson Wednesday

Now that we've covered "Red, Green, Refactor", Gradle, and JUnit, let's create another project together using these tools and workflows. In this lesson we will create a program that returns whether a user-provided year is a leap year.

Again, you are not required to code along with this lesson when completing it as homework. Read through to review the concepts covered here. You'll follow along to code the leap year application with your partner tomorrow.

To internalize the Red, Green, Refactor workflow, keep this lesson open while following along.

## Leap Years

Almost every 4 years we experience something called a "leap year". These years are special because they contain 366 days instead of 365. Normally February only has 28 days. During leap years it has 29.

These are the 3 criteria that determine whether a year is a leap year:

• If a year is evenly divisible by 4 it is a leap year.
• If a year is divisible by 400 it is a leap year.
• If a year is evenly divisible by 100 (and not divisible by 400) it is not a leap year.

Our program will use these criteria to evaluate a year, and return whether it is a leap year.

## Setup

Before we can write tests we must set up our project. Let's do that now.

### Project Directory

As you know, Gradle requires a particular project structure. We'll create this now:

• Create a leap-year directory.
• In this directory create a src subdirectory for your source code.
• In the src subdirectory, create main and test subdirectories. These will contain the main application logic and test files, respectively.
• In both the main and test subdirectories, create a java subdirectory.
• In the leap-year/src/main/java directory, create a LeapYear.java file to contain your back-end logic.
• In the leap-year/src/test/java directory, create a LeapYearTest.java file. It will house the JUnit tests for your back-end logic.
• In the top-level of the leap-year directory, create your build.gradle file.

Your directory structure should now look like this:

``````leap-year/
└── src/
├── main/
│   └── java/
│       └── LeapYear.java
└── test/
└── java/
└── LeapYearTest.java
``````

We can delay creating the App.java file. JUnit only tests back-end logic, not our user interface. Since App.java will contain our user interface, we can wait to create it.

``````apply plugin: 'java'
apply plugin: 'application'

archivesBaseName = "leap-year"
version = '1.0'
mainClassName = "LeapYear"

repositories {
mavenCentral()
}

dependencies {
testCompile group: 'junit', name: 'junit', version: '4.+'
}
``````

### Class Files

Let's set up our `LeapYear` class file. We'll declare the classes and method, but will not include any logic within them. This is to avoid the compiler errors we saw in Testing with JUnit.

leap-year/src/main/java/LeapYear.java
``````public class LeapYear {

public boolean isLeapYear(int year) {
// eventually put your code here
return false;
}

}
``````

Remember, the `\$ gradle test` command first compiles source code, then runs tests on the compiled code. If a test includes classes or methods that aren't declared, the compiler will halt and throw an error. If the project does not compile successfully, the tests cannot run. Thus, we need to declare any classes or methods used in the test to avoid compiler errors. This allows us to run our tests, and confirm new tests are failing appropriately.

Since our `isLeapYear()` method will return a boolean, we add `return false`. This allows our application will compile properly.

### Test Files

Next, let's set up our test file:

leap-year/src/test/java/LeapYearTest.java
``````import org.junit.*;
import static org.junit.Assert.*;

public class LeapYearTest {

}

``````

Here, we import the JUnit testing library: `org.junit.*;`, and JUnit's assertion library: `static org.junit.Assert.*;`. Then, we declare our `LeapYearTest` class, leaving it empty for now.

## The Behavior-Driven Development Process

Now that everything is in place, we may begin the Behavior-Driven Development process. (Also known as the Red, Green, Refactor workflow).

### Identify Simplest Behavior

The first step in Red, Green, Refactor: Identify the program's simplest possible behavior.

This behavior should also remain applicable for the life of the program. Because we want to avoid changing previous specs as we build future specs.

In our case, the simplest possible behavior is determining whether a year is divisible by 4. The first criteria in checking whether a year is a leap year.

### Writing a Coded Test

The second step in Red, Green, Refactor: Write a coded test.

In our test file, we'll begin by declaring our test method:

leap-year/src/test/java/LeapYearTest.java
``````import org.junit.*;
import static org.junit.Assert.*;

public class LeapYearTest {

@Test
public void isLeapYear_forNumberDivisibleByFour_true() {
// test code will eventually go here.
}

}
``````
• We add the required `@Test` annotation. This informs the compiler that JUnit will be responsible for running this code.
• We declare the method as `public void` because all JUnit tests must be `public void`.
• `isLeapYear` refers to the name of the method this spec will be testing.
• `forNumberDivisibleByFour` is a brief description of the behavior this spec will test.
• `true` is the output we are anticipating for the example input we provide momentarily.

Next, we'll add the content to our newly-declared test:

LeapYearTest.java
``````import org.junit.*;
import static org.junit.Assert.*;

public class LeapYearTest {

@Test
public void isLeapYear_forNumberDivisibleByFour_true() {
LeapYear leapYear = new LeapYear();
assertEquals(true, leapYear.isLeapYear(2012));
}

}
``````
• To test our `isLeapYear()` method we must create an instance of the `LeapYear` class.
• The `assertEquals()` method instructs JUnit to compare its two arguments. Essentially, we're telling it to check whether `leapYear.isLeapYear(2012)` successfully returns `true`.

### Make Sure the Test Fails

The third step in Red, Green, Refactor: Before coding, make sure the test fails.

Run `\$ gradle test` and see what happens. It should look something like this:

``````\$ gradle test
:compileJava
:processResources UP-TO-DATE
:classes
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test

LeapYearTest > isLeapYear_forNumberDivisibleByFour_true FAILED
java.lang.AssertionError at LeapYearTest.java:9

1 test completed, 1 failed
:test FAILED

FAILURE: Build failed with an exception.

* What went wrong:
> There were failing tests. See the report at: file:///Users/staff/Desktop/java/leap-year/build/reports/tests/test/index.html

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 3.639 secs

``````

Copy and paste your line that looks like: `file:///Users/staff/Desktop/java/leap-year/build/reports/tests/test/index.html` into your browser to view a detailed test report. Remember, you can refresh this page to see the current status of your tests every time you run `\$ gradle test`.

### Implement the Behavior

The fourth step in Red, Green, Refactor: Implement the behavior with the least amount of code possible.

We know we'll eventually need to check if the year is divisible by 100 or 400. But we only add code for our first behavior: Returning `true` when the year is divisible by 4.

leap-year/src/main/java/LeapYear.java
``````...
public boolean isLeapYear(int year) {
return year % 4 == 0;
}
...
``````

### Run the Automated Test(s)

The fifth step in Red, Green, Refactor: Run tests to confirm the new spec passes.

`\$ gradle test` should return no error messages:

``````\$ gradle test

:compileJava
:processResources UP-TO-DATE
:classes
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test

BUILD SUCCESSFUL

Total time: 1.229 secs
``````

And if we refresh our test report, we see the following:

### Make Sure Previous Tests Pass

The sixth step in Red, Green, Refactor: Confirm all previous tests still pass.

Since this is currently our only test, we can skip this step.

## Refactor

The seventh step in Red, Green, Refactor: Check if you can refactor. If so, refactor and confirm all tests still pass.

Since the logic we've added so far is very brief, we can't refactor quite yet, but you should always check.

### Repeat

The eighth and final step in Red, Green, Refactor: Repeat the process with the next simplest behavior.

### Identify a Behavior

The first step in Red, Green, Refactor: Identify the program's simplest possible behavior.

In our case, the next simplest behavior is returning `false` for years not divisible by four.

### Write a Coded Test

The second step in Red, Green, Refactor: Write a coded test.

Our next test will look like this:

LeapYearTest.java
``````…
@Test
public void isLeapYear_forNumbersNotDivisibleByFour_false(){
LeapYear leapYear = new LeapYear();
assertEquals(false, leapYear.isLeapYear(1999));
}
...
``````

Again, we create an instance of the `LeapYear` class. Then, we use JUnit's `assertEquals()` method to confirm `isLeapYear()` correctly returns `false` when provided `1999`.

### Make Sure the Test Fails

The third step in Red, Green, Refactor: Before coding, make sure the test fails.

Next, before we implement any new logic, we need to confirm this spec fails correctly.

We can run `\$ gradle test` and see the following:

``````\$ gradle test

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test

BUILD SUCCESSFUL

Total time: 1.993 secs
``````

If we refresh our test report in the browser, Click on Classes, then click on LeapYearTest we see this:

If a test passes before you implement logic to make it pass, take a very careful look at your code. First, confirm the test itself is written correctly. Our test does look correct. There are no syntax errors. We included the correct `@Test` annotation. We instantiated the required instance of `LeapYear`. We provided the correct arguments to `assertEquals()`. It looks good.

If the test looks good, double-check your logic. Is there anything already present in this that would make this test pass? Right now, our `isLeapYear()` method looks like this:

leap-year/src/main/java/LeapYear.java
``````...
public boolean isLeapYear(int year) {
return year % 4 == 0;
}
...
``````

We're returning either `true` or `false` depending on whether `year` is evenly divisible by 4. `1999` from our last test isn't divisible by 4, so the method returned `false`.

Alright, we can confirm that this test isn't passing incorrectly. The logic we implemented to pass the previous test simply covers this behavior too. Sometimes this will happen. When it does, just be very careful in confirming the test is passing for the right reasons.

Since this behavior was actually already present, and all tests pass, we've completed the following Red, Green, Refactor steps:

1. Implement the behavior with the least amount of code possible.
2. Run the automated test to confirm it passes.
3. Make sure all previous tests still pass.

### Refactor

The seventh step in Red, Green, Refactor: Check if you can refactor. If so, refactor and confirm all tests still pass.

Our logic is still contained in a single, DRY line of code. There isn't much room for refactoring quite yet. We can move to the next step.

### Repeat

The eighth and final step in Red, Green, Refactor: Repeat the process with the next simplest behavior.

### Identify a Behavior

The first step in Red, Green, Refactor: Identify the program's simplest possible behavior.

Based on the leap year criteria, the next simplest behavior is returning `false` for numbers divisible by 100, since those years cannot be leap years.

### Write a Coded Test

The second step in Red, Green, Refactor: Write a coded test.

Let's add a spec for this behavior, too:

LeapYearTest.java
``````...
@Test
public void isLeapYear_forMultiplesOfOneHundred_false() {
LeapYear leapYear = new LeapYear();
assertEquals(false, leapYear.isLeapYear(1900));
}
...
``````

### Make Sure the Test Fails

The third step in Red, Green, Refactor: Before coding, make sure the test fails.

If we run `\$ gradle test` again, all tests should pass except the most recent we've added:

``````\$ gradle test

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test

LeapYearTest > isLeapYear_forMultiplesOfOneHundred_false FAILED
java.lang.AssertionError at LeapYearTest.java:21

3 tests completed, 1 failed
:test FAILED

FAILURE: Build failed with an exception.

* What went wrong:
> There were failing tests. See the report at: file:///Users/staff/Desktop/java/leap-year/build/reports/tests/test/index.html

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 1.927 secs

``````

If we look at the stack trace from the test report it reads: `java.lang.AssertionError: expected:<false> but was:<true>`. This means that the test expected to receive `false` when running our `isLeapYear()` method with the sample input. But it actually received `true` instead. Since this was not the anticipated output, the test fails.

### Implement the Behavior

The fourth step in Red, Green, Refactor: Implement the behavior with the least amount of code possible.

Next, let's add the minimum amount of code to pass this test. We can simply add to our existing conditional:

LeapYear.java
``````public boolean isLeapYear(int year) {
if ( year % 100 == 0 ) {
return false;
} else {
return year % 4 == 0;
}
}
``````

### Run the Automated Tests

The fifth step in Red, Green, Refactor: Run tests to confirm the new spec passes.

Run the tests once more:

``````\$ gradle test

:compileJava
:processResources UP-TO-DATE
:classes
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test

BUILD SUCCESSFUL

Total time: 1.529 secs
``````

Everything passes! Perfect!

### Make Sure Previous Tests Pass

The sixth step in Red, Green, Refactor: Confirm all previous tests still pass.

If we look at the report from the previous section, we can easily confirm all tests are still passing.

### Refactor

The seventh step in Red, Green, Refactor: Check if you can refactor. If so, refactor and confirm all tests still pass.

Next, we'll double-check if we can refactor. Again, since we've been adding the smallest amount of code possible when implementing each behavior, there isn't much room for refactoring.

### Repeat

The eighth and final step in Red, Green, Refactor: Repeat the process with the next simplest behavior.

There is one last behavior our program will need to implement.

### Identify a Behavior

The first step in Red, Green, Refactor: Identify the program's simplest possible behavior.

Since any year divisible by 400 is a leap year, the application should return `true` for years divisible by 400.

### Write a Coded Test

The second step in Red, Green, Refactor: Write a coded test.

We'll add a test for this final behavior:

LeapYearTest.java
``````...
@Test
public void isLeapYear_forMultiplesOfFourHundred_true() {
LeapYear leapYear = new LeapYear();
assertEquals(true, leapYear.isLeapYear(2000));
}
...
``````

### Make Sure the Test Fails

The third step in Red, Green, Refactor: Before coding, make sure the test fails.

We'll run our new test to ensure it fails correctly:

``````\$ gradle test

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test

LeapYearTest > isLeapYear_forMultiplesOfFourHundred_true FAILED
java.lang.AssertionError at LeapYearTest.java:27

4 tests completed, 1 failed
:test FAILED

FAILURE: Build failed with an exception.

* What went wrong:
> There were failing tests. See the report at: file:///Users/staff/Desktop/java/leap-year/build/reports/tests/test/index.html

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 2.384 secs

``````

### Implement the Behavior

The fourth step in Red, Green, Refactor: Implement the behavior with the least amount of code possible.

And we'll implement the smallest amount of code to create this behavior:

LeapYear.java
``````public boolean isLeapYear(int year) {
if ( year % 400 == 0 ) {
return true;
} else if ( year % 100 == 0 ) {
return false;
} else {
return year % 4 == 0;
}
}
``````

### Run the Automated Tests

The fifth step in Red, Green, Refactor: Run tests to confirm the new spec passes.

We'll run our tests again:

``````\$ gradle test

:compileJava
:processResources UP-TO-DATE
:classes
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test

BUILD SUCCESSFUL

Total time: 2.102 secs

``````

### Make Sure Previous Tests Pass

The sixth step in Red, Green, Refactor: Confirm all previous tests still pass.

Great! Both our most current and all previous tests pass! We should have a completely green test report, and a fully functional `isLeapYear()` method.

### Refactor

The seventh step in Red, Green, Refactor: Check if you can refactor. If so, refactor and confirm all tests still pass.

Because we've added so little logic for each behavior, our code is already DRY. But always double-check whether you can refactor. If you can, confirm all tests pass after making changes.

## Front-End User Interface

Now that we've built DRY, well-tested back-end logic, we can add our user interface. Since the back-end code is well-tested, if any errors occur when we launch our program we'll know the bug resides in the user interface logic. After all, the back-end logic is already vetted. Doesn't that make tracking down bugs so much easier?

Create an App.java file in the leap-year/src/main/java directory.

Next, add the necessary boilerplate code. We'll also import the `Console` class and declare an instance of it, because we'll need it to gather user input:

leap-year/src/main/java/App.java
``````import java.io.Console;

public class App {
public static void main(String[] args) {
Console myConsole = System.console();
}
}

``````

Next, we'll add a prompt to ask users to enter a year:

leap-year/src/main/java/App.java
``````import java.io.Console;

public class App {
public static void main(String[] args) {
Console myConsole = System.console();
System.out.println("Enter a year, we'll tell you if it's a leap year:")
}
}

``````

We'll gather the user's input and parse it from a `String` into an `Integer`:

leap-year/src/main/java/App.java
``````import java.io.Console;

public class App {
public static void main(String[] args) {
Console myConsole = System.console();
System.out.println("Enter a year, we'll tell you if it's a leap year:");
int intYear = Integer.parseInt(stringYear);
}
}
``````

Finally, we'll create an instance of the `LeapYear` class, call our `isLeapYear()` method, and print its results for the user:

leap-year/src/main/java/App.java
``````import java.io.Console;

public class App {
public static void main(String[] args) {
Console myConsole = System.console();
System.out.println("Enter a year, we'll tell you if it's a leap year:");
int intYear = Integer.parseInt(stringYear);
LeapYear leapYear = new LeapYear();
boolean leapYearResult = leapYear.isLeapYear(intYear);
System.out.println("Is that year a leap year?" + leapYearResult);
}
}

``````

We can use Gradle's \$ gradle compileJava` command to compile our program:

``````\$ gradle compileJava

:compileJava UP-TO-DATE

BUILD SUCCESSFUL

Total time: 0.729 secs

``````

Next, in a new terminal tab, we'll navigate to the build/classes/main directory containing our Gradle-compiled code:

``````\$ cd build/classes/main
``````

...launch our application:

``````\$ java App
``````

And we should see the following:

``````\$ java App

Enter a year, we'll tell you if it's a leap year:
``````

If we provide a year, it should tell us whether it is a leap year:

``````\$ java App

Enter a year, we'll tell you if it's a leap year:
>2018

Is that year a leap year? false
``````

Awesome! Continue to follow the "Red, Green, Refactor" workflow closely as you create Java applications. Using Behavior-Driven Development in this fashion is required for the rest of the course. Reference the Red, Green, Refactor lesson for as long/often as you need to. Eventually, it will become second nature!

Example GitHub Repo for Leap Year

## Overview

• This lesson does not address any new concepts, it is simply another demonstration of what creating a Java application using Behavior-Driven Development and the "Red, Green, Refactor" workflow looks like. For cheatsheets on any of the concepts covered here, visit the lessons these concepts were introduced in:

## Example

Example GitHub Repo for Leap Year