{"id":"unit-testing-junit","slug":"junit","title":"Unit tests with JUnit","text":"The `check` method of the last step is a test written by hand. Java programmers usually write their tests with a library instead, and a widely used one is **JUnit**. This module uses JUnit 4, the version the MOOC uses. (JUnit 5, the newer version, works much the same way, with different imports and a few different names and details. For example, `@Before`, which comes later in this module, is `@BeforeEach` there, and doubles can be compared without a delta.)\n\nJUnit tests are methods in a class of their own, a **test class**, next to the class they test. Here a parking garage has a number of spots, and cars park and leave. The page shows the garage and its test class, and then the report of running the tests:\n\n```java\n// ==== Garage.java ====\npublic class Garage {\n    private int spots;\n    private int parked;\n\n    public Garage(int spots) {\n        this.spots = spots;\n        this.parked = 0;\n    }\n\n    public boolean park() {\n        if (this.parked < this.spots) {\n            this.parked++;\n            return true;\n        }\n        return false;\n    }\n\n    public void leave() {\n        if (this.parked > 0) {\n            this.parked--;\n        }\n    }\n\n    public int freeSpots() {\n        return this.spots - this.parked;\n    }\n}\n// ==== GarageTest.java ====\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.Test;\n\npublic class GarageTest {\n    @Test\n    public void newGarageHasEverySpotFree() {\n        Garage garage = new Garage(3);\n        assertEquals(3, garage.freeSpots());\n    }\n\n    @Test\n    public void parkingTakesOneSpot() {\n        Garage garage = new Garage(3);\n        garage.park();\n        assertEquals(2, garage.freeSpots());\n    }\n\n    @Test\n    public void fullGarageTakesNoMoreCars() {\n        Garage garage = new Garage(2);\n        garage.park();\n        garage.park();\n        garage.park();\n        assertEquals(0, garage.freeSpots());\n    }\n}\n```\n\n```output\nGarageTest: 3 tests\n  fullGarageTakesNoMoreCars: passed\n  newGarageHasEverySpotFree: passed\n  parkingTakesOneSpot: passed\n3 of 3 tests passed\n```\n\nJUnit runs the tests and collects their results. The report above is how Java Arena shows those results. On your own computer, an editor shows the same results in a window of its own.\n\nPiece by piece:\n\n- The test class is an ordinary public class. By custom it's named after the class it tests, with `Test` at the end: `GarageTest` tests `Garage`.\n- `import org.junit.Test;` brings in `@Test`, and `import static org.junit.Assert.assertEquals;` brings in JUnit's method `assertEquals`, so the tests can call it by its short name. (A **static import** brings in a static method of another class. Without it, every call would be written `Assert.assertEquals(...)`.)\n- `@Test` on the line before a method marks the method as a test. It's an **annotation**: a note on the method, which JUnit reads. A test method is `public void` and takes no parameters.\n- There's no `main`. JUnit finds the methods marked `@Test` and runs each one on its own. Each test makes a Garage of its own, so one test can't spoil another, and the order they run in doesn't matter. (JUnit picks the order itself. Java Arena's report lists the tests in alphabetical order.)\n- `assertEquals(expected, actual)` compares two values: first the value the test expects, then the code that gives the real value. When they're equal, the test goes on. When they aren't, the test stops right there and fails.\n- The report lists every test with `passed` or `FAILED`, and then how many passed.\n\nA test uses the class the way any other code would. `park()` returns true or false, and these tests don't use that value, which is fine.\n\n### When a test fails\n\nNow someone \"simplifies\" `park` and forgets about the full garage. The tests are the same:\n\n```java\n// ==== Garage.java ====\npublic class Garage {\n    private int spots;\n    private int parked;\n\n    public Garage(int spots) {\n        this.spots = spots;\n        this.parked = 0;\n    }\n\n    public boolean park() {\n        this.parked++;\n        return true;\n    }\n\n    public void leave() {\n        if (this.parked > 0) {\n            this.parked--;\n        }\n    }\n\n    public int freeSpots() {\n        return this.spots - this.parked;\n    }\n}\n// ==== GarageTest.java ====\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.Test;\n\npublic class GarageTest {\n    @Test\n    public void newGarageHasEverySpotFree() {\n        Garage garage = new Garage(3);\n        assertEquals(3, garage.freeSpots());\n    }\n\n    @Test\n    public void parkingTakesOneSpot() {\n        Garage garage = new Garage(3);\n        garage.park();\n        assertEquals(2, garage.freeSpots());\n    }\n\n    @Test\n    public void fullGarageTakesNoMoreCars() {\n        Garage garage = new Garage(2);\n        garage.park();\n        garage.park();\n        garage.park();\n        assertEquals(0, garage.freeSpots());\n    }\n}\n```\n\n```output\nGarageTest: 3 tests\n  fullGarageTakesNoMoreCars: FAILED\n    java.lang.AssertionError: expected:<0> but was:<-1>\n    at GarageTest.fullGarageTakesNoMoreCars(GarageTest.java:25)\n  newGarageHasEverySpotFree: passed\n  parkingTakesOneSpot: passed\n2 of 3 tests passed\n```\n\nThe failed test has two more lines:\n\n- `java.lang.AssertionError: expected:<0> but was:<-1>`: an assertion failed. The test expected 0 free spots, and the garage said -1: it let a third car into two spots.\n- `at GarageTest.fullGarageTakesNoMoreCars(GarageTest.java:25)`: the line of the test where it failed.\n\nThe test's name tells what went wrong before you read any further: a full garage took one more car. So the place to look is `park`. The other two tests still pass. Each test checks one thing, so a failure points at one thing.\n\nThat's also why the order of the two values matters. Written the other way around, `assertEquals(garage.freeSpots(), 0)` fails just the same, but its message says `expected:<-1> but was:<0>`, which sends you looking for the wrong problem. The expected value goes first.\n\nIf the code a test calls crashes, the test fails too, and the report shows the exception, such as `java.lang.ArithmeticException: / by zero`, with the line of your own code where it happened.\n\nIn a project on your own computer, test classes usually live in a folder of their own (in the MOOC's projects, `src/test/java`), and the editor has a button that runs them. Here, the test class is one more tab, and \"Run my tests\" runs it.\n","task":"`GarageTest` has a new test, `leavingFreesASpot`, that's nearly done: it makes a garage with 3 spots, parks two cars and lets one leave. But it doesn't check anything yet, so it passes whatever `leave` does. Add an `assertEquals` at its end that checks that 2 spots are free. The checks run your tests on the Garage as it is, where every test should pass, and on a Garage whose `leave` never frees a spot, where your test should fail.\n","kind":"code","seed":"// ==== GarageTest.java ====\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.Test;\n\npublic class GarageTest {\n    @Test\n    public void parkingTakesOneSpot() {\n        Garage garage = new Garage(3);\n        garage.park();\n        assertEquals(2, garage.freeSpots());\n    }\n\n    @Test\n    public void leavingFreesASpot() {\n        Garage garage = new Garage(3);\n        garage.park();\n        garage.park();\n        garage.leave();\n        // Check here that 2 spots are free.\n    }\n}\n\n// ==== Garage.java ====\npublic class Garage {\n    private int spots;\n    private int parked;\n\n    public Garage(int spots) {\n        this.spots = spots;\n        this.parked = 0;\n    }\n\n    public boolean park() {\n        if (this.parked < this.spots) {\n            this.parked++;\n            return true;\n        }\n        return false;\n    }\n\n    public void leave() {\n        if (this.parked > 0) {\n            this.parked--;\n        }\n    }\n\n    public int freeSpots() {\n        return this.spots - this.parked;\n    }\n}\n","solution":"// ==== GarageTest.java ====\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.Test;\n\npublic class GarageTest {\n    @Test\n    public void parkingTakesOneSpot() {\n        Garage garage = new Garage(3);\n        garage.park();\n        assertEquals(2, garage.freeSpots());\n    }\n\n    @Test\n    public void leavingFreesASpot() {\n        Garage garage = new Garage(3);\n        garage.park();\n        garage.park();\n        garage.leave();\n        assertEquals(2, garage.freeSpots());\n    }\n}\n\n// ==== Garage.java ====\npublic class Garage {\n    private int spots;\n    private int parked;\n\n    public Garage(int spots) {\n        this.spots = spots;\n        this.parked = 0;\n    }\n\n    public boolean park() {\n        if (this.parked < this.spots) {\n            this.parked++;\n            return true;\n        }\n        return false;\n    }\n\n    public void leave() {\n        if (this.parked > 0) {\n            this.parked--;\n        }\n    }\n\n    public int freeSpots() {\n        return this.spots - this.parked;\n    }\n}\n","hints":["The test above it shows the shape: `assertEquals(` the number you expect, a comma, and the call that gives the real value `)`.","Add `assertEquals(2, garage.freeSpots());` as the last line of `leavingFreesASpot`. The expected value, 2, goes first."],"tests":[{"name":"The Garage as it is","stdin":"","junit":"GarageTest","outcome":"pass","expect":"","hidden":false},{"name":"A Garage whose leave never frees a spot","stdin":"","junit":"GarageTest","outcome":"fail","replace":{"Garage.java":"public class Garage {\n    private int spots;\n    private int parked;\n\n    public Garage(int spots) {\n        this.spots = spots;\n        this.parked = 0;\n    }\n\n    public boolean park() {\n        if (this.parked < this.spots) {\n            this.parked++;\n            return true;\n        }\n        return false;\n    }\n\n    public void leave() {\n        if (this.parked < 0) {\n            this.parked--;\n        }\n    }\n\n    public int freeSpots() {\n        return this.spots - this.parked;\n    }\n}\n"},"expect":"","hidden":false},{"name":"A Garage whose leave adds a car instead","stdin":"","junit":"GarageTest","outcome":"fail","replace":{"Garage.java":"public class Garage {\n    private int spots;\n    private int parked;\n\n    public Garage(int spots) {\n        this.spots = spots;\n        this.parked = 0;\n    }\n\n    public boolean park() {\n        if (this.parked < this.spots) {\n            this.parked++;\n            return true;\n        }\n        return false;\n    }\n\n    public void leave() {\n        if (this.parked > 0) {\n            this.parked++;\n        }\n    }\n\n    public int freeSpots() {\n        return this.spots - this.parked;\n    }\n}\n"},"expect":"","hidden":true}],"require":[{"pattern":"\\bassertEquals\\s*\\(","min":2,"message":"Add an `assertEquals` to the end of `leavingFreesASpot`."}],"forbid":[],"more":[{"task":"A shopping cart adds up the prices of its products, in cents. Someone rewrote its `total()` with an index loop, and one version they tried skips the first product. `CartTest` has one test, but it can't tell the versions apart: an empty cart costs 0 either way.\n\nWrite a second test: put a few products with different prices in a cart, and check `total()` with `assertEquals`. Your tests should pass on the Cart as it is, and fail on the version that skips the first product.\n","kind":"code","seed":"// ==== CartTest.java ====\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.Test;\n\npublic class CartTest {\n    @Test\n    public void emptyCartCostsNothing() {\n        Cart cart = new Cart();\n        assertEquals(0, cart.total());\n    }\n}\n\n// ==== Cart.java ====\nimport java.util.ArrayList;\n\npublic class Cart {\n    private ArrayList<Integer> prices;\n\n    public Cart() {\n        this.prices = new ArrayList<>();\n    }\n\n    public void add(int cents) {\n        this.prices.add(cents);\n    }\n\n    public int itemCount() {\n        return this.prices.size();\n    }\n\n    public int total() {\n        int total = 0;\n        for (int i = 0; i < this.prices.size(); i++) {\n            total += this.prices.get(i);\n        }\n        return total;\n    }\n}\n","solution":"// ==== CartTest.java ====\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.Test;\n\npublic class CartTest {\n    @Test\n    public void emptyCartCostsNothing() {\n        Cart cart = new Cart();\n        assertEquals(0, cart.total());\n    }\n\n    @Test\n    public void totalAddsUpEveryPrice() {\n        Cart cart = new Cart();\n        cart.add(250);\n        cart.add(400);\n        cart.add(99);\n        assertEquals(749, cart.total());\n    }\n}\n\n// ==== Cart.java ====\nimport java.util.ArrayList;\n\npublic class Cart {\n    private ArrayList<Integer> prices;\n\n    public Cart() {\n        this.prices = new ArrayList<>();\n    }\n\n    public void add(int cents) {\n        this.prices.add(cents);\n    }\n\n    public int itemCount() {\n        return this.prices.size();\n    }\n\n    public int total() {\n        int total = 0;\n        for (int i = 0; i < this.prices.size(); i++) {\n            total += this.prices.get(i);\n        }\n        return total;\n    }\n}\n","hints":["A new test is a new method with `@Test` before it: `@Test public void totalAddsUpEveryPrice() { ... }`. In it, make a Cart, `add` a few prices, and check the total.","For example `cart.add(250);`, `cart.add(400);` and `cart.add(99);`, then `assertEquals(749, cart.total());`. Different prices matter: with the same price twice, some wrong totals would still come out right."],"tests":[{"name":"The Cart as it is","stdin":"","junit":"CartTest","outcome":"pass","expect":"","hidden":false},{"name":"A Cart whose total skips the first product","stdin":"","junit":"CartTest","outcome":"fail","replace":{"Cart.java":"import java.util.ArrayList;\n\npublic class Cart {\n    private ArrayList<Integer> prices;\n\n    public Cart() {\n        this.prices = new ArrayList<>();\n    }\n\n    public void add(int cents) {\n        this.prices.add(cents);\n    }\n\n    public int itemCount() {\n        return this.prices.size();\n    }\n\n    public int total() {\n        int total = 0;\n        for (int i = 1; i < this.prices.size(); i++) {\n            total += this.prices.get(i);\n        }\n        return total;\n    }\n}\n"},"expect":"","hidden":false},{"name":"A Cart whose total adds the first price again and again","stdin":"","junit":"CartTest","outcome":"fail","replace":{"Cart.java":"import java.util.ArrayList;\n\npublic class Cart {\n    private ArrayList<Integer> prices;\n\n    public Cart() {\n        this.prices = new ArrayList<>();\n    }\n\n    public void add(int cents) {\n        this.prices.add(cents);\n    }\n\n    public int itemCount() {\n        return this.prices.size();\n    }\n\n    public int total() {\n        int total = 0;\n        for (int i = 0; i < this.prices.size(); i++) {\n            total += this.prices.get(0);\n        }\n        return total;\n    }\n}\n"},"expect":"","hidden":true}],"require":[],"forbid":[]},{"task":"A treadmill's speed goes up and down 1 km/h at a time, but never below 1 or above 12. The Treadmill class is right. `TreadmillTest` isn't: one of its tests fails, and the other passes but has its two values the wrong way around.\n\nRun the tests and read the report. Fix the test that expects the wrong number (the class does what it should, so the test is what's wrong), and put the expected value first in the other one. The fixed tests should pass on the Treadmill and still catch a treadmill that goes below 1 km/h.\n","kind":"code","seed":"// ==== TreadmillTest.java ====\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.Test;\n\npublic class TreadmillTest {\n    @Test\n    public void fasterAddsOne() {\n        Treadmill treadmill = new Treadmill(5);\n        treadmill.faster();\n        assertEquals(treadmill.getSpeed(), 6);\n    }\n\n    @Test\n    public void neverSlowerThanOne() {\n        Treadmill treadmill = new Treadmill(3);\n        treadmill.slower();\n        treadmill.slower();\n        treadmill.slower();\n        assertEquals(0, treadmill.getSpeed());\n    }\n}\n\n// ==== Treadmill.java ====\npublic class Treadmill {\n    private int speed;\n\n    public Treadmill(int speed) {\n        this.speed = speed;\n    }\n\n    public void faster() {\n        if (this.speed < 12) {\n            this.speed++;\n        }\n    }\n\n    public void slower() {\n        if (this.speed > 1) {\n            this.speed--;\n        }\n    }\n\n    public int getSpeed() {\n        return this.speed;\n    }\n}\n","solution":"// ==== TreadmillTest.java ====\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.Test;\n\npublic class TreadmillTest {\n    @Test\n    public void fasterAddsOne() {\n        Treadmill treadmill = new Treadmill(5);\n        treadmill.faster();\n        assertEquals(6, treadmill.getSpeed());\n    }\n\n    @Test\n    public void neverSlowerThanOne() {\n        Treadmill treadmill = new Treadmill(3);\n        treadmill.slower();\n        treadmill.slower();\n        treadmill.slower();\n        assertEquals(1, treadmill.getSpeed());\n    }\n}\n\n// ==== Treadmill.java ====\npublic class Treadmill {\n    private int speed;\n\n    public Treadmill(int speed) {\n        this.speed = speed;\n    }\n\n    public void faster() {\n        if (this.speed < 12) {\n            this.speed++;\n        }\n    }\n\n    public void slower() {\n        if (this.speed > 1) {\n            this.speed--;\n        }\n    }\n\n    public int getSpeed() {\n        return this.speed;\n    }\n}\n","hints":["The report says `expected:<0> but was:<1>`. From 3, three steps down would be 0, but the treadmill stops at 1, as it should. So the test's 0 is the mistake.","Change the 0 to 1 in `neverSlowerThanOne`, and write the other one as `assertEquals(6, treadmill.getSpeed());`."],"tests":[{"name":"The Treadmill as it is","stdin":"","junit":"TreadmillTest","outcome":"pass","expect":"","hidden":false},{"name":"A Treadmill that goes below 1 km/h","stdin":"","junit":"TreadmillTest","outcome":"fail","replace":{"Treadmill.java":"public class Treadmill {\n    private int speed;\n\n    public Treadmill(int speed) {\n        this.speed = speed;\n    }\n\n    public void faster() {\n        if (this.speed < 12) {\n            this.speed++;\n        }\n    }\n\n    public void slower() {\n        this.speed--;\n    }\n\n    public int getSpeed() {\n        return this.speed;\n    }\n}\n"},"expect":"","hidden":false},{"name":"A Treadmill whose faster adds 2 km/h","stdin":"","junit":"TreadmillTest","outcome":"fail","replace":{"Treadmill.java":"public class Treadmill {\n    private int speed;\n\n    public Treadmill(int speed) {\n        this.speed = speed;\n    }\n\n    public void faster() {\n        if (this.speed < 12) {\n            this.speed += 2;\n        }\n    }\n\n    public void slower() {\n        if (this.speed > 1) {\n            this.speed--;\n        }\n    }\n\n    public int getSpeed() {\n        return this.speed;\n    }\n}\n"},"expect":"","hidden":true}],"require":[],"forbid":[{"pattern":"\\bassertEquals\\s*\\(\\s*\\w+\\s*\\.\\s*getSpeed","message":"Put the expected value first: `assertEquals(6, treadmill.getSpeed());`."}]}]}