Skip to content

Lab 2 - Would You Like Fries With That?

In this lab, you'll add support for ordering Fries, starting with the MealBuilder class, adding that property to the request object, and then have the API Controller method process it and return the price.

Add Fries Support to MealBuilder

Starting with the test, go to MealBuilderTest and add the following:

  @Test
  public void orderWithBurgerCheeseAndLargeFriesIs11Dollars() throws Exception {
    MealBuilder mealBuilder = new MealBuilder();
    mealBuilder.addBurgerString("cheese");
    mealBuilder.withFries("large");

    // use the build() method to create a meal order

    // assert that the price is burger (5) + cheese (1) + large-fries (5)
    assertThat(...
  }

Run it and it should fail.

Make Test Pass

In order to make this test pass, you will have to:

  1. Add the withFries method to MealBuilder and store the size in a String instance variable called friesSize

  2. Inside the MealBuilder.build() method, add code to add the fries to the meal order:

    public MealOrder build() {   
      // existing build code here
    
    **Add the Fries to the mealOrder HERE**     
    
      return mealOrder;
    }      
    

    Question

    What happens for tests that didn't specify any Fries?

    Do NOT change the tests to "fix" this problem: fix the code.

  3. Make sure the MealBuilderTest tests pass.


Run All Tests

Make sure all of your tests pass before going to the next step.


Update the API Controller

Now let's make the API support ordering fries. First let's make sure we have a failing test.

Add Fries to Request

  1. Add the friesSize property to the MealOrderRequest class: instance variable, and getter/setter.

Add Test for Fries

  1. Go to the MealOrderApiControllerTest test and write a new test that is similar to the one that's already there: instead of setting the drink, set the friesSize property, e.g.:

    public class MealOrderApiControllerTest {
    
      // ... other test...
    
      @Test
      public void ...your test name here...() throws Exception {
        // GIVEN a request (similar to above)...
        mealOrderRequest.setFriesSize("large"); // $5
    
        // WHEN calling controller.mealOrder...
    
        // THEN assertThat the response has the right price...
      }
    }
    

    Outcome?

    What is the total price for an order with a large fries? Make sure to assert that.

  2. Make sure the test fails before continuing.

Add Support in Controller

  1. Add code in the mealOrder method in MealOrderApiController so that if a Fries Size is specified, it's added to the meal order.

  2. Does the MealOrderApiControllerTest now pass? It should!


Run All Tests

Make sure all of your tests pass before going to the next step.


Try it Out

  1. Start the app by running the MealKioskApplication class

  2. Use this URL in either curl or Postman: localhost:8080/api/mealorder

    curl on Windows

    curl -v -d "{\"burger\": \"cheese\", \"drinkSize\": \"large\", \"friesSize\": \"regular\"}" -H "Content-Type: application/json" localhost:8080/api/mealorder
    

    curl on Mac

    curl -v -d '{"burger": "cheese", "drinkSize": "large", "friesSize": "regular"}' -H 'Content-Type: application/json' localhost:8080/api/mealorder
    

    Postman

    Do a POST to localhost:8080/api/mealorder with the following JSON

    {"burger": "cheese", "drinkSize": "large", "friesSize": "regular"}
    
  3. You should see the following JSON because Burger w/Cheese (6), Large Drink (2), and Regular Fries ($3) = $11.

    {"price": 11}
    

Instructor Check-in

Before going any further, have the instructor look over your work.

Bonus (Optional)

The builder could use some improvements to become more "fluent". It would be nice if instead of

MealBuilder mealBuilder = new MealBuilder();
mealBuilder.addBurgerString("none");
mealBuilder.withDrink("regular");
mealBuilder.withFries("large");

MealOrder mealOrder = mealBuilder.build();

we could write

MealOrder mealOrder = MealBuilder.builder()
  .burger("none")
  .drink("regular")
  .fries("large")
  .build()

This is called a "fluent" or "chained" builder.

Rename Methods

First we'll rename the methods on the builder using IntelliJ IDEA's Refactoring > Rename tool.

  1. Find the addBurgerString method
  2. With the cursor on that method, use the Refactor > Rename menu item (or Shift + F6) to rename it to burger
  3. Find the withDrink method and rename it to drink
  4. Find the withFries method and rename it to fries

Make sure all tests still pass before continuing.

Return Builder

Now we'll change all the builder methods to return an instance of the builder (itself).

  1. In the burger method, change the signature to return a MealBuilder and then return this, so you want the method to look like:

    public MealBuilder burger(String burgerOrderString) {
      burgerOrder = burgerOrderString;
      return this;
    }
    
  2. Do the same for drink

  3. And the same for fries

Make sure all tests still pass before continuing.

Create Builder Method

Create a new method, builder() that is static and returns a new instance of the MealBuilder.

Change Tests to Use Fluent Builder

Inside of the MealBuilderTest test class, pick one of the tests that builds from multiple items and convert it so that it uses this new fluent syntax, e.g., write a Builder test that uses:

MealOrder mealOrder = MealBuilder.builder()
  .burger("none")
  .drink("regular")
  .fries("large")
  .build()