Frage

Ich möchte ein Ergebnis verspotten. Ernsthaft. Ich refaktoriere einen großen komplizierten Code, der Daten vom Ergebnis analysiert, und ich möchte, dass sich mein Code identisch verhalten. Daher muss ich einen Unit -Test schreiben, damit das Stück neu gestaltet wird, um dies zu testen.

Nach dem Googeln kam ich mit 2 Ideen:

  1. Verwenden Sie EasyMock, schreiben Sie looooong spottesreiche Sequenz. Sehr schlechte Lösung: Es ist schwer, anfängliche Daten hinzuzufügen, Daten zu ändern, große Testversprechen.
  2. Verwenden Sie Apache Derby oder HSQLDB, um In-Memory-DB zu erstellen, es aus Datei- oder String-Array ausfüllen und mit einigen magischen InMemoryDButils.Query (SQL) abfragen. Verwenden Sie dann dieses Ergebnis. Leider habe ich keine magischen InmemoryDButils gefunden, um den Test schnell zu schreiben :-). IBM -Artikel "Isolierte Einheitenprüfung der Persistenz mit Derby" scheint jedoch in Ordnung zu sein, was ich brauche ...

Der zweite Ansatz sieht etwas einfacher und viel unterstützbarer aus.

Was würden Sie beraten, ein solches Schein zu erstellen? (Natürlich trotz Ärzte :-)? Vermisse ich eine Augenbraue Eine Silberkugel? Möglicherweise ist Dbunit das Werkzeug dafür?

War es hilfreich?

Lösung

Dbunit präsentiert meines Wissens kein Ergebnissatz, obwohl es Ihnen dabei hilft, Ihre in Speicherdatenbank zu füllen.

Ich würde sagen, dass ein spöttischer Rahmen an dieser Stelle der falsche Ansatz ist. Bei Spott geht es darum, Verhalten und Interaktion zu testen und nicht nur Daten zurückzugeben, sondern dass es Ihnen wahrscheinlich im Weg steht.

Ich würde stattdessen entweder eine Ergebnis -Set -Schnittstelle implementieren oder einen dynamischen Proxy einer Ergebnis -Set -Schnittstelle zu einer Klasse erstellen, die die Methoden implementiert, die Ihnen wichtig sind, ohne den gesamten Ergebnissatz implementieren zu müssen. Sie werden wahrscheinlich feststellen, dass eine Klasse so einfach ist wie die Verwaltung einer In -Speicherdatenbank (vorausgesetzt, der zu testende Datensatz ist konsistent) und wahrscheinlich einfacher zu debuggen.

Sie können diese Klasse mit Dbunit sichern, in der Sie eine Momentaufnahme Ihres Ergebnisssatzes mit Dbunit aufnehmen und DBUNIT während des Tests von XML zurücklesen lassen und Ihr Dummy -Ergebnis -Set die Daten aus DBUNIT -Klassen lesen lassen. Dies wäre ein vernünftiger Ansatz, wenn die Daten leicht komplex wären.

Ich würde mich für die in Speicherdatenbank entscheiden, wenn die Klassen so gekoppelt wären, dass sie Daten lesen müssen, die als Teil desselben Tests geändert wurden. Selbst dann würde ich in Betracht ziehen, eine Kopie der realen Datenbank zu verwenden, bis Sie es geschafft haben, diese Abhängigkeit auseinander zu ziehen.

Eine einfache Methode für die Erzeugung von Proxy:

private static class SimpleInvocationHandler implements InvocationHandler {
    private Object invokee;

    public SimpleInvocationHandler(Object invokee) {
        this.invokee = invokee;
    }

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        method = invokee.getClass().getMethod(method.getName(), method.getParameterTypes());
        if (!method.isAccessible()) {
            method.setAccessible(true);
        }
        try {
            return method.invoke(invokee, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }
}

public static <T> T generateProxy(Object realObject, Class... interfaces) {
    return (T) Proxy.newProxyInstance(realObject.getClass().getClassLoader(), interfaces, new SimpleInvocationHandler(realObject));
}

Andere Tipps

Ich hatte Erfolg mit der MockResultset -Klasse von hier aus: http://mockrunner.sourceforge.net/. Sie können eine Klasse erstellen, die die Ergebnissens -Schnittstelle implementiert, und können die Werte für jede Spalte und Zeile festlegen.

Wenn Ihre Methoden mit Ergebnissen von angemessener Größe arbeiten, sollten Sie in der Lage sein, Tests zu erstellen, die die Werte zurückgeben, die Sie ziemlich einfach benötigen.

Hier ist ein einfaches Beispiel:

MockResultSet rs = new MockResultSet("myMock");

rs.addColumn("columnA", new Integer[]{1});
rs.addColumn("columnB", new String[]{"Column B Value"});
rs.addColumn("columnC", new Double[]{2});

// make sure to move the cursor to the first row
try
{
  rs.next();
}
catch (SQLException sqle)
{
  fail("unable to move resultSet");
}

// process the result set
MyObject obj = processor.processResultSet(rs);

// run your tests using the ResultSet like you normally would
assertEquals(1, obj.getColumnAValue());
assertEquals("Column B Value", obj.getColumnBValue());
assertEquals(2.0d, obj.getColumnCValue());

Ich habe etwas für denselben Fall geschrieben. Sie können das Ergebnis mit Mockito verspotten. Sie können auch über die Scheinzeilen des Ergebnissetets gehen, indem Sie das Ergebnis verspottet.Next () mit diesem Code -Stück.

// two dimensional array mocking the rows of database.
String[][] result = { { "column1", "column2" }, { "column1", "column2" } };

@InjectMocks
@Spy
private TestableClass testableClass;

@Mock
private Connection connection;

@Mock
private Statement statement;

@Mock
private ResultSet resultSet;

@BeforeTest
public void beforeTest() {
    MockitoAnnotations.initMocks(this);
}

@BeforeMethod
public void beforeMethod() throws SQLException {
    doAnswer(new Answer<Connection>() {
        public Connection answer(InvocationOnMock invocation)
                throws Throwable {
            return connection;

        }
    }).when(testableClass).getConnection();

    when(connection.createStatement()).thenReturn(statement);
    when(statement.executeQuery(anyString())).thenReturn(resultSet);
    final AtomicInteger idx = new AtomicInteger(0);
    final MockRow row = new MockRow();

    doAnswer(new Answer<Boolean>() {

        @Override
        public Boolean answer(InvocationOnMock invocation) throws Throwable {
            int index = idx.getAndIncrement();
            if (result.length > index) {
                String[] current = result[index];
                row.setCurrentRowData(current);
                return true;
            } else
                return false;

        }

        ;
    }).when(resultSet).next();

    doAnswer(new Answer<String>() {

        @Override
        public String answer(InvocationOnMock invocation) throws Throwable {
            Object[] args = invocation.getArguments();
            int idx = ((Integer) args[0]).intValue();
            return row.getColumn(idx);
        }

        ;
    }).when(resultSet).getString(anyInt());
}

static class MockRow {
    String[] rowData;

    public void setCurrentRowData(String[] rowData) {
        this.rowData = rowData;
    }

    public String getColumn(int idx) {
        return rowData[idx - 1];
    }
}

Mockrunner Kann eine CSV- oder XML -Datei laden und automatisch ein MockResultset erstellen. Es kann auch die Verbindung und Anweisung verspotten, sodass alle Ihre JDBC -Dinge einfach funktionieren, ohne Ihrem Klassenpfad einen JDBC -Treiber hinzuzufügen.

Falls zutreffend, können Sie das Ergebnissatz von Ihrer realen Datenquelle übernehmen, serialisieren und die Datei speichern. Dann könnten Sie das Ergebnis für jeden Ihrer Unit -Tests deserialisieren, und Sie sollten gut gehen.

Solange Sie den größten Teil nicht anrufen ResultSet Methoden, ich würde wahrscheinlich nur eine abgrenzte Textdatei in ein zweidimensionales Array laden und die Methoden implementieren, die ich tatsächlich benötigte, so UnsupportedOperationException (Das ist die Standardimplementierung für stubige Methoden in meiner IDE).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top