Skip to content

Lab 3 - Repository

Goal

Have a way of saving and finding orders in memory, behind a single interface.

Important

Be sure to skim through all of the steps before getting started.

A. Give CoffeeOrder an Identity

Make the CoffeeOrder an Entity.

  1. Add a Long id private member variable to the CoffeeOrder class.

    Important

    Make sure you create the member variable exactly: its type is Long and its name is id (all lower-case).

  2. Create a getter & setter for the id property.

    • Use IntelliJ to generate the getter & setter using ⌘ + N

B. Create Repository Interface

Create a new interface named CoffeeOrderRepository (using New > Java Class from the File menu)

Add the following code:

public interface CoffeeOrderRepository {

  CoffeeOrder findOne(Long id);

  CoffeeOrder save(CoffeeOrder coffeeOrder);

  List<CoffeeOrder> findAll();

}

C. Create Empty Implementation

  1. Create a new class named FakeCoffeeOrderRepository that implements the CoffeeOrderRepository interface and start with the following code:

    public class FakeCoffeeOrderRepository implements CoffeeOrderRepository {
    
      public FakeCoffeeOrderRepository() {}
    
      public FakeCoffeeOrderRepository(CoffeeOrder... coffeeOrders) {
        // You can iterate through the coffeeOrders array like this:
        for (CoffeeOrder coffeeOrder : coffeeOrders) {
          // process each coffeeOrder here
        }
        // You can also convert it directly to a List:
        //     List<CoffeeOrder> coffeeOrderList = Arrays.asList(coffeeOrders);
        // See: https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList-T...-
      }
    
      public CoffeeOrder findOne(Long id) {
        throw new UnsupportedOperationException(); 
      }
    
      public CoffeeOrder save(CoffeeOrder coffeeOrder) {
        throw new UnsupportedOperationException(); 
      }
    
      public List<CoffeeOrder> findAll() {
      }
    
    }
    

D. FindAll Implementation

Keep Method Signatures

You are not allowed to change any of the method signatures that are defined in the CoffeeOrderRepository. You must abide by this defined interface.

  1. Create a new Test Class called CoffeeOrderRepositoryFindTest

  2. For each of the following, write a failing test, then make that test pass:

    1. If findAll() is called and there are no orders, it must return an empty List

    2. If there are orders, findAll() must return all of them in a List

      • Use this test to get you started:
        @Test
        public void findAllShouldReturn2Orders() {
          CoffeeOrder coffeeOrder1 = new CoffeeOrder();
          coffeeOrder1.setId(1L);
          CoffeeOrder coffeeOrder2 = new CoffeeOrder();
          coffeeOrder2.setId(2L);
        
          CoffeeOrderRepository repo = new FakeCoffeeOrderRepository(coffeeOrder1, coffeeOrder2);
          assertThat(repo.findAll())
            .hasSize(2);
        }
        
    3. Make sure all tests pass before continuing.

E. Find One Implementation

Which Collection Class?

What is appropriate Java Collection class to use to store the coffeeOrders so that it's easy to find CoffeeOrder's by their id?

  1. Open the CoffeeOrderRepositoryFindTest test class

  2. Implement the findOne() method (remember to write failing tests first):

    1. If there's no CoffeeOrder with that id, return null.
    2. If there exists a CoffeeOrder with the given id, return it
    3. Make sure all tests pass before continuing.

F. Save Implementation

  1. Create a new test class named CoffeeOrderRepositorySaveTest

  2. Implement the save() method, which stores the given order in the repository so it can be found later.

    1. IF the incoming coffeeOrder object's id property is ALREADY set, DON'T change the id, just store the order (replacing the existing instance, just like an "update" might).

    2. IF the coffeeOrder came in with NO id (null), SET it with a UNIQUE one that the repository generates

      Unique?

      How will you guarantee that each ID is unique?

    3. Return the CoffeeOrder object that must now have its id set (i.e., id must NOT be null)

Here's a test to use to ensure that each newly saved CoffeeOrder is given an ID that's different from other newly saved CoffeeOrders.

@Test
public void newlySavedCoffeeOrdersHaveUniqueIds() {
  CoffeeOrderRepository coffeeOrderRepository = new FakeCoffeeOrderRepository();
  CoffeeOrder coffeeOrder1 = new CoffeeOrder();
  coffeeOrder1 = coffeeOrderRepository.save(coffeeOrder1);
  CoffeeOrder coffeeOrder2 = new CoffeeOrder();
  coffeeOrder2 = coffeeOrderRepository.save(coffeeOrder2);

  assertThat(coffeeOrder1.getId())
      .isNotEqualTo(coffeeOrder2.getId());
}

Once you've completed the above steps,
check in with the instructor to review your code.


Optional

  1. Implement the "delete" functionality by adding the following method to the CoffeeOrderRepository interface:

    void delete(CoffeeOrder coffeeOrder);
    
  2. Implement the following behavior in your FakeCoffeeOrderRepository, remember to write a failing test first:

NOTE: Put tests for delete into a new Test class named CoffeeOrderRepositoryDeleteTest

  • Deleting a coffeeOrder means that trying to find it by its id will return null -- as if the coffeeOrder was never saved.

    NOTE: Don't modify the coffeeOrder object that's being deleted -- it will continue to have the id that was assigned upon save

  • If null reference for the CoffeeOrder is passed in, throw an IllegalArgumentException

  • If a CoffeeOrder with an id that's not found is passed in, throw an IllegalArgumentException


Once you've completed the above steps,
check in with the instructor to review your code.


References

Article: "Mocks Aren't Stubs" by Martin Fowler

Book: xUnit Test Patterns by Gerard Meszaros