Schlagwort-Archive: Konstruktor mocken

Mocken von Konstruktoren mit PowerMock und JUnit

Auch in diesem Artikel soll es wieder um das Mocken von Objekten mit PowerMock gehen. Aber im Gegensatz zum Mocken von statischen Methoden wie im letzten Artikel soll es nun um das Mocken von Konstruktoren gehen.

Dazu wird wiederum ein kleines Beispiel mit einem Zeitbezug als Veranschaulichung dienen. In der folgenden Klasse wird kontrolliert, ob das aktuelle Datum vor oder nach einem fest definierten Daum liegt.

package de.sevendroids.java.powermock.sample;

import java.util.Calendar;
import java.util.Date;

/**
 * @author 7droids.de (FA)
 */
public class PowerMockSampleClassConstructor {
  private static final Date FIXEDDATE;
  static {
    Calendar cal = Calendar.getInstance();
    cal.set(2011, Calendar.OCTOBER, 27, 0, 0, 0);
    cal.set(Calendar.MILLISECOND, 0);
    FIXEDDATE = cal.getTime();
  }

  public static boolean isTodayAfterFixedDate() {
    Date today = new Date();
    return today.after(FIXEDDATE);
  }
}

Auch hier wäre eine Variante, die Erzeugung des Date-Objektes aus der Methode auszulagern und der Methode nur das fertige Datum zu übergeben. Damit würde aber die Klasse nur zu Testzwecken unnötig aufgebläht werden oder aber die Aufrufer müssten geändert werden.

Eine Alternative, bei der man zum Testen ohne eine Codeänderung auskommt, bietet die Verwendung von PowerMock. PowerMock kann mit den beiden bekanntesten Testframeworks JUnit und TestNG sowei mit den Mockingframeworks EasyMock und Mockito verwendet werden. Z.B. so mit JUnit und Mockito:

package de.sevendroids.java.powermock.sample;

import static org.junit.Assert.assertTrue;
import static org.powermock.api.mockito.PowerMockito.verifyNew;
import static org.powermock.api.mockito.PowerMockito.whenNew;

import java.util.Calendar;
import java.util.Date;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

/**
 * @author 7droids.de (FA)
 */
// 1: Define special runner for PowerMock
@RunWith(PowerMockRunner.class)
// 2: Define class to test
@PrepareForTest(PowerMockSampleClassConstructor.class)
public class PowerMockSampleClassConstructorTest {

  /**
   * Test method for
   * {@link PowerMockSampleClassConstructor#isTodayAfterFixedDate()}.
   *
   * @throws Exception
   */
  @Test
  public void verifyThatIsTodayAfterFixedDateForEndOfOctober2011()
           throws Exception {
    // 3: Create a date for 30th of October
    Calendar cal = Calendar.getInstance();
    cal.set(2011, Calendar.OCTOBER, 30);
    Date lastDayInOctober = cal.getTime();
    // 4: Define return value for constructor
    whenNew(Date.class).withNoArguments().thenReturn(lastDayInOctober);
    // 5: Call the method to test
    assertTrue(PowerMockSampleClassConstructor.isTodayAfterFixedDate());
    // 6: Constructor called only once
    verifyNew(Date.class).withNoArguments();
  }
}

Zum besseren Verständnis seien die einzelnen, nummerierte Zeilen genauer beschrieben:

  1. Zeile: Hier wird ein eigener Runner von PowerMock definiert, der die folgenden Funktionen erst ermöglicht.
  2. Zeile: Mit der Annotation @PrepareFor wird die zu testende Klasse bekannt gegeben. Es handelt sich dabei nicht um die Klasse, dessen Konstruktor gemockt werden soll, sondern um die Klasse, in der der Konstruktor gemockt werden soll.
  3. Zeile: Nun wird das Mockobjekt erzeugt, dass anstelle des Konstruktors zurückgeliefert werden soll.
  4. Zeile: In dieser Zeile wird definiert, dass jedes Mal, wenn der leere Konstruktor von java.util.Date aufgerufen wird, das vorher erzeugte Mockobjekt zurückgegeben werden soll.
  5. Zeile: Der eigentliche Aufruf der zu testenden Methode.
  6. Zeile: Zum Abschluss wird noch kontrolliert, ob der leere Konstruktor nur einmal aufgerufen wurde.

Wie ich gezeigt habe, ist durch die Verwendung von PowerMock das Mocken von Konstruktoren sehr einfach. Im nächsten Artikel werde ich die den Zugriff auf private Instanz- und Objektvariablen mit Hilfe von PowerMock beschreiben.