Where do you even start?
Now that you know a little about unit testing, let’s write one! How do we do this? Well, with complex applications, the main concern is focusing on the system under test - in other words, the thing being tested!
Um...What is a system under test? 😮
Have you ever gotten your eyes tested? You’re usually plopped into a seat with a built-in gadget and with a big chart full of letters in front of you.
The optometrist will ask you some questions, have you read the chart, check our eyes using gadgets, give you a prescription, and send you on your way. They don't switch or change the distance of the chart or install a different gadget on the chair. Everything is set up and ready so they can focus on running their test, not on how it’s done. (You're the thing being tested! 😉)
It's the same thing with unit tests. The class you’re testing is your SUT. You use testing frameworks to help focus on your SUT so that running and reporting on the automated tests is handled by the framework.
Set up your build tools and frameworks
Before we can test, we’ll need a Java project. Let’s create one!
I’m going to show you how to write JUnit tests by building a very basic calculator. We’re going to start off by creating a class which can add two numbers, and we’ll do this by writing our JUnit tests first! So let’s get started and create a new Java project. See if you can follow along!
As you saw we had to make sure that the build tool Maven knew about JUnit before we could use it as we’re introducing third-party code which our own code uses. These are called dependencies. In the screencast, when we told IntelliJ to add a Maven dependency on JUnit, it updated a special file called pom.xml. Maven uses this to decide which version of JUnit to use and make sure that we use it only for testing. You should now also be able to run your tests outside of an IDE by typing.
mvn test
Get your files in order for JUnit
To create a unit test with JUnit for a class, you’ll start by creating another class. This new one will hold all of the tests you’ll use to check your original. This is usually created under the src/test/java folder of your project, and the test class is named after the one being tested. So, you'll find all the tests for the Calculator class in CalculatorTest.
Structuring your first unit test
Now that everything is set up to test, how do you actually do it? Well, you have to set up a test within the JUnit framework:
Let's walk through each of the steps in the image one by one:
Step 1: Import JUnit annotations
To turnCalculatorTest
into a new JUnit test, start by importing JUnit’s@Test
annotation with the following code:import org.junit.*;
.
Step 2: Place
@Test
in front of a method
To create a test with JUnit, make a new class and add the@Test
annotation above each method which performs your test.Step 3: Write a descriptive name
The method name should clearly describe what is being tested. It’s important to give your tests a name which describes what the test is checking for.
How do you actually structure the content of your tests? To write reliable tests, it makes sense to follow the popular acronym, AAA. (This has nothing to do with automobiles. 😉) It stands for arrange, act, and assert. The goal of this structure is to keep tests independent and avoid interfering with one another. And guess what? We're going to act, arrange, and assert as our next steps:
Let's go through each of the steps in the image above:
Step 4: Arrange - Set up the class under test
Arrange is another way of saying set up. When you write a unit test for a class, you start by setting up an instance of the class you are going to test. Do this by callingnew
on it. This is called your class under test(CUT), or in other words, the thing you’re testing!Step 5: Act - Call the method you’re testing
Now that you’ve got your test arranged, you’ll act on this. Basically, you prod at it with your testing wand by calling its methods. The methods should do something which you can check for, or return a result.Step 6: Assert - Check the result with an assertion
Now that you know what you’re checking, you assert your expectations. You want to compare an expected value with the actual value returned by the method you’re testing. If they match, your test passes. If they don’t, you fix it so they pass. You do this by adding an assertion!
An assertion is a statement which calls out what you think should happen in your test. If an assertion does not turn out to be correct when the test runs, then it fails. It also fails the whole JUnit test. It's best to have only one assertion per test. This way, you immediately know which assertion is failing and can focus on fixing one thing at a time.
Now, that you know what the steps are, let's take a closer look at that image again:
In the image above, the result of calculatorUnderTest.add(1,1)
is compared with the number 2 using assertEquals
. Here, you’re testing the assertion that two values are equal. This is just one of the assertions JUnit makes available when you import org.junit (like in Step 1). assertEquals
simply tests that the returned value from calculatorUnderTest.add(1,1)
is the same as the value you expected to get back.
Okay, it's set up! But how do I run it?
Whether you’re using IntelliJ or Eclipse, you can now right-click on the test name and select Run. The above example was run using IntelliJ. Have a look at the green tick. Can you tell what it’s testing? 😎 Adding two positive numbers correctly! And it looks like the test has passed. ✅
Had the assertion failed because the add method was buggy, you would have seen something like:
You can see that the test failed (It has a round cross beside it) as the Actual (0 in this case) didn’t match the Expected value (2).
Using TDD: red-green-refactor!
You might have noticed that we started writing tests before anything else in the code. This follows a technique called test-driven development, or TDD. Using this technique means the code you build remains focused on passing those tests. Did you notice how writing the test before the code allowed us to describe what the add method would look like? From there, we just had to allow our IDE to create it for us. 🙃
Okay, I get the gist from what we did, but how exactly does this work?
Kent Beck, the creator of TDD, introduced many developers to the following pattern:
In this pattern, you loop through the following steps:
Write a failing unit test. 🔴
Write the code to make the test pass. ✅
Clean up the code without failing the tests. 🔶
Write the next test and repeat! 🔄
This is called red-green-refactor. Failed tests are described as red. Much like a traffic signal, red tells you to stop and make your code work.🚦When they pass, they are green. Green tells you to go and refactor. This simply means that you can try and make your code more readable or elegant without changing the way it behaves.
Because the test is already in place, it lets you know right away if you break any behavior, ensuring that you’re always focused on functionality first.
It turns out that if you write your code after your test, that code is easier to test. That’s because it’s made to be tested! Testable code is usually clearer code. Remember, try and keep your tests focused on one thing. As you write a focused test for each class, TDD encourages you to build software out of lots of little classes, each doing one thing well. This adds to the clarity of the code. It’s easier to follow one thing than 50. 😛
As you test software, you also learn about the code you need to build to pass those tests. This also shapes a minimal and modular design, meaning that your code isn’t clumped together in a few classes. Modular code is flexible and very easy to change. Why should you care if it’s easy to change? Any software you build at work will last for many years and continuously change as your users’ needs also change. This keeps you in a job! TDD makes the job easier. 😎
Try it out for yourself!
Have a go at adding a Calculator.multiply
method! Remember to write your test first and make it go red before you write the code! You can clone the repository and add your own code to it!
git clone https://github.com/OpenClassrooms-Student-Center/AchieveQualityThroughTestingInJava.git git checkout p1-c3-sc-1-to-3
Or use your IDE to clone the repository and check out the branch p1-c3-sc-1-to-3. You can now explore the examples from the screencast and try running the tests with mvn test
.
Let's recap!
JUnit is a testing framework which helps you focus on validating classes.
To use JUnit, you need to add a testing dependency to your build tool.
Build software using red-green-refactor where you:
Start with red failing tests which describe what you plan to build.
Make the tests pass and go green by building the code in the most direct way.
Improve the readability of your code by refactoring it without breaking the test.
Now that you've got the basics down, let's make our tests more understandable in the next chapter!