Mocking dependencies in unit tests using JMockIt

Ein weiterer Blogpost aus dem Firmenblog, wieder in Englisch.

Garage & GarageTest

This test case demonstrate the use of JMockIt and its Expectations to resolve dependencies in unit tests. Expectations are a way to easily mock the behavior of an object in unit tests, without creating interfaces, classes and other overhead. Take a look at the full unit test first, and I’ll explain what’s done there later. You can find the interface Garage and the classes CheapGarage and EngineFactory at the end of this blogpost.

Now, back to the method testRepairWithExpectationEngineFactory(). The EngineFactory is a dependency buried down in the CheapGarage class that is responsible for replacing the Engine in a Car. There is a mocked instance of EngineFactory in this unit test that will return a new DieselEngine every time the method instantiate() is called with any kind of argument. This way I can control exactly how the hidden call to a factory behaves. JMockIt has a bunch of other useful features and I recommend it for all unit tests. If you care about your tests and try to avoid testing dependencies instead of your logic, then you should start using JMockIt today.

Car.java

package de.kopis.example;

public class Car {
	protected Engine engine;
	
	public Car(Engine e) {
		engine = e;
	}
	
	public void replaceEngine(Engine e) {
		engine = e;
	}
}

Engine.java

package de.kopis.example;

public interface Engine {}

class GasolineEngine implements Engine {}
class DieselEngine implements Engine {}

Garage/CheapGarage.java

package de.kopis.example;

public interface Garage {
  public Car repairEngine(Car car);
}

abstract class AbstractGarage implements Garage {
  public abstract Car repairEngine(Car car);
}

class CheapGarage extends AbstractGarage {
  public Car repairEngine(Car car) {
    replaceEngineWithNewInstance(car);
    return car;
  }

  private void replaceEngineWithNewInstance(Car car) {
    try {
      Engine newEngine = EngineFactory.instantiate(car.engine);
      car.replaceEngine(newEngine);
    } catch ( InstantiationException e ) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch ( IllegalAccessException e ) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

class EngineFactory {
  public EngineFactory() {}

  public static Engine instantiate(Engine engine) throws InstantiationException, IllegalAccessException {
    Class<? extends Engine> engineClass = engine.getClass();
    Engine newEngine = engineClass.newInstance();
    return newEngine;
  }
}

GarageTest.java

package de.kopis.example;

import static org.junit.Assert.*;

import mockit.Expectations;

import org.junit.Test;

public class GarageTest {
  @Test
  public void testRepair() {
    Garage g = new CheapGarage();
    Engine expectedEngine = new GasolineEngine();
    Car expectedCar = new Car(expectedEngine);
    Car actualCar = g.repairEngine(expectedCar);
    assertSame(expectedCar, actualCar);
    assertNotSame(expectedCar.engine, expectedEngine);
  }

  @Test
  public void testRepairWithExpectationEngineFactory() throws InstantiationException, IllegalAccessException {
    final Engine expectedEngine = new DieselEngine();
    final Engine actualEngine = new GasolineEngine();
    final Garage g = new CheapGarage();
    final Car expectedCar = new Car(actualEngine);
    // here it is still the Engine built into the car
    assertSame(expectedCar.engine, actualEngine);

    new Expectations() {
      EngineFactory mock;
      {
        mock.instantiate(actualEngine); returns(new DieselEngine());
      }
    };

    Car actualCar = g.repairEngine(expectedCar);
    assertSame(expectedCar, actualCar);
    // normally this will be a GasolineEngine, because that was built into the car
    // but because of the mocked EngineFactory, we get a DieselEngine instead
    assertTrue(expectedCar.engine instanceof DieselEngine);
    assertNotSame(expectedCar.engine, expectedEngine);
  }
}

Using Mortbays Jetty as embedded servlet container in unit tests

Ich habe diesen Blogeintrag in einem Firmenblog veröffentlicht, daher ist er in Englisch. Und bitte:

Today I created a simple unit test that runs Mortbays Jetty as an embedded servlet container for a unit test with JUnit 4. It’s quite simple to run the ServletTester and add Servlets to it, so you can create HTTP requests and assert against the responses.

To run Jetty you need the following JAR files in your classpath:

  • jetty-6.X.Y.jar
  • jetty-servlet-tester-6.X.Y.jar
  • jetty-util-6.X.Y.jar
  • servlet-api-2.5-*.jar

The HelloServletTest simply sets up Jetty to initialize a servlet, runs one test and stops Jetty after it. The HelloServlet I used for the first test. It’s the obvious Hello World example.

Now you can remove HelloServlet</code>, add your own servlet classes and go unit test them. ;-)</p>


IntelliJ IDEA wird Open Source!

Letzte Woche habe ich noch eine schöne Nachricht via Twitter bekommen: IntelliJ IDEA wird Open Source! Auf der Community-Seite von JetBrains kann man sich die Preview der neuen Version runterladen. Ich denke, damit wird das Early Acess Program abgelöst, bei dem man sich schon seit längerer Zeit die kommende Version von IDEA kostenlos herunterladen und testen konnte.

Ich habe mit dieser IDE angefangen, als ich frisch in Java eingestiegen bin. Zu der Zeit war Eclipse noch keine ernsthafte Konkurrenz. Vielleicht ist die steigende Beliebtheit und die Funktionsvielfalt von Eclipse mit ein Grund für die Öffnung von IDEA, vielleicht wollen die Entwickler aber wirklich etwas zurückgeben. Bei Reddit bin ich über einen Link zu einem Blogpost gestolpert, der genau das vermutet hat: JetBrains geht den Bach runter und versucht nun über Open Source den Abstieg aufzuhalten.

Wir werden sehen. Mir fallen jetzt -ausser SUN- keine Firmen ein, die auf dem absteigenden Ast durch Open Source ihrer Produkte noch einmal die Kurve geschafft haben, aber bestimmt gibt es noch mehr Gründe. 😉

Sourcecode Highlighter

Ich teste gerade ein Plugin für Quelltexte:

/**
 * This is a comment.
 */
import java.io.*;

public class Test extends JFrame {
    public static void main(String... args) {
        System.out.println("Hello, World!");
    }
}