PUBLIC OBJECT

EasyMock and OutOfMemoryError: PermGen space

I wrote a test using the easy-to-use EasyMock Unit-testing API:

package com.publicobject.pizzadelivery;

import junit.framework.TestCase;
import org.easymock.classextension.EasyMock;

public class PizzaDeliveryPersonTest extends TestCase {
  private PizzaStore pizzaStore;
  private Customer customer;
  private Order order;
  private Address address;
  private DeliveryPerson deliveryPerson;

  @Override
  public void setUp() {
    pizzaStore = EasyMock.createMock(PizzaStore.class);
    order = EasyMock.createMock(Order.class);
    address = EasyMock.createMock(Address.class);
    customer = EasyMock.createMock(Customer.class);

    EasyMock.expect(pizzaStore.getNextOrder())
        .andReturn(order).anyTimes();
    EasyMock.expect(order.getAddress())
        .andReturn(address).anyTimes();
    EasyMock.expect(order.getPrice())
         .andReturn(new Money(17)).anyTimes();
    EasyMock.expect(address.getCoordinates())
        .andReturn(new GpsCoordinates(30, 40)).anyTimes();
    EasyMock.expect(customer.acceptOrder(order))
        .andReturn(new Money(20).anyTimes();

    EasyMock.replay(pizzaStore);
    EasyMock.replay(order);
    EasyMock.replay(address);
    EasyMock.replay(customer);
  }

  public void testDeliveryPerson() {
    doTestDeliveryPerson(new BasicPizzaDeliveryPerson());
  }

  public void testDeliveryPersonWithNoGasInCar() {
    BasicPizzaDeliveryPerson deliveryPerson = new BasicPizzaDeliveryPerson()
    deliveryPerson.getCar().setFuel(0);
    doTestDeliveryPerson(deliveryPerson);
  }

  public void testDeliveryPersonWhoSpeaksFrench() {
    BasicPizzaDeliveryPerson deliveryPerson = new BasicPizzaDeliveryPerson()
    deliveryPerson.setNativeLanguage(Language.FRENCH);
    doTestDeliveryPerson(deliveryPerson);
  }

  public void testRealTimeDeliveryPerson() {
    PizzaDeliveryPerson deliveryPerson = new RealTimePizzaDeliveryPerson()
    doTestDeliveryPerson(deliveryPerson);
  }

  public void testMinimumWageDeliveryPerson() {
    BasicPizzaDeliveryPerson deliveryPerson = new BasicPizzaDeliveryPerson()
    deliveryPerson.setHourlyWage(new Money(7));
    doTestDeliveryPerson(deliveryPerson);
  }

  public void doTestDeliveryPerson(PizzaDeliveryPerson deliveryPerson) {
     assertTrue(deliveryPerson.getTotalMoney().toDollars() == 0);
     deliveryPerson.setStore(pizzaStore);
     deliveryPerson.runDelivery();
     assertTrue(deliveryPerson.getTotalMoney().toDollars() == 20);
     assertTrue(deliveryPerson.getTotalTips().toDollars() == 3);
  }
}`</pre>
...but when I ran it in my continuous build, it failed due to a memory leak:
<pre>`java.lang.OutOfMemoryError: PermGen space`</pre>
It turns out that every time I call `EasyMock.createMock()`[*](#), a piece of memory is allocated that can **never be reclaimed!**

My hacky fix was to make all the mocked objects `static`. Now they only get created once, not once for each of the 5 test methods:
<pre>`public class PizzaDeliveryPersonTest extends TestCase {
  private **static** PizzaStore pizzaStore;
  private **static** Customer customer;
  private **static** Order order;
  private **static** Address address;
  private **static** DeliveryPerson deliveryPerson;

  **static** {
    pizzaStore = EasyMock.createMock(PizzaStore.class);
    order = EasyMock.createMock(Order.class);
    address = EasyMock.createMock(Address.class);
    customer = EasyMock.createMock(Customer.class);

    EasyMock.expect(pizzaStore.getNextOrder())
        .andReturn(order).anyTimes();
    EasyMock.expect(order.getAddress())
        .andReturn(address).anyTimes();
    EasyMock.expect(order.getPrice())
         .andReturn(new Money(17)).anyTimes();
    EasyMock.expect(address.getCoordinates())
        .andReturn(new GpsCoordinates(30, 40)).anyTimes();
    EasyMock.expect(customer.acceptOrder(order))
        .andReturn(new Money(20).anyTimes();

    EasyMock.replay(pizzaStore);
    EasyMock.replay(order);
    EasyMock.replay(address);
    EasyMock.replay(customer);
  }

  ...
}

It gets the job done, but not well. The disadvantages of this approach:

  • I need to use `anyTimes()` on my objects so their methods can be called repeatedly
  • The code is ugly
  • I still have a memory leak, it's just a bit smaller

    It would be a great fix for EasyMock if multiple calls to EasyMock.createMock(PizzaStore.class) could share the same generated class object.