Wie wertvoll sind Snapshot-Tests?

Die meisten Frontend-Entwickler kennen Snapshot-Tests aus dem Test-Framework ‚Jest‘. Diese Tests versprechen laut offizieller Webseite folgendes

Snapshot tests are a very useful tool whenever you want to make sure your UI does not change unexpectedly.

https://jestjs.io/docs/snapshot-testing, aufgerufen am 29.12.2021

Wollen wir uns einmal kurz die Frage stellen, was ist an diesem Versprechen dran und wie wertvoll sind diese Snapshot-Tests wirklich. Zunächst einmal der Hinweis, auf die Test Pyramide (siehe: Die Test-Pyramide der Software und warum sie so wichtig ist) – wir befinden uns auf der Ebene der Unit Tests, unsere Anforderung ist es, sicherzustellen, dass sich Komponenten so verhalten wie wir es erwarten.

Bevor wir Snapshot-Tests benutzen können, muss ein Testfall her. Diesen imaginären Testfall bietet uns die Website von ‚Jest‘ ebenfalls

import React from 'react';
import renderer from 'react-test-renderer';
import Link from '../Link.react';

it('renders correctly', () => {
  const tree = renderer
    .create(<Link page="http://www.facebook.com">Facebook</Link>)
    .toJSON();
  expect(tree).toMatchSnapshot();
});

Der Snapshot dieses Tests sieht folgendermaßen aus

exports[`renders correctly 1`] = `
<a
  className="normal"
  href="http://www.facebook.com"
  onMouseEnter={[Function]}
  onMouseLeave={[Function]}
>
  Facebook
</a>
`;

Hier fallen einige Dinge auf, die Komponente wird DOM ähnlich auf unserer Platte als „snap“ Datei gespeichert. Doch was passiert wenn wir unsere Implementierung ändern würden? Welche Aussagekraft hat solch ein Test?

In den folgenden Abschnitten möchte ich auf die Nachteile der Snapshot-Tests eingehen. Diese sind mit Hypothesen in den Überschriften gegliedert, während ich im Absatz näher darauf eingehen werde.

1. Snapshot-Tests sind Implementierungsdetailabhängig

Wie zuvor gezeigt, werden Implementierungsdetails gespeichert und somit zwangsweise mit getestet. Dies lässt sich daran erkennen, dass die Link Komponente gezwungen ist ein Anchor-Tag in den DOM zu schreiben. Wäre z.B. ein DIV würde dieser Test fehlschlagen. Demnach kommen auch noch alle Props wie Name, Test-IDs uvm. der Komponente. Sprich Snapshot-Tests testen Implementierungsdetails anstelle der Komponente.

Demnach lässt sich sagen, sollte es zu einem Refactoring kommen, sind diese Art der Tests zwangsläufig rot und bieten somit keine Sicherheit, dass die Komponente ordnungsgemäß funktioniert.

2. Snapshot-Tests stellen sicher, dass Komponenten ordnungsgemäß angezeigt werden

Als ich anfing Snapshot-Tests zu benutzen, war ich ebenfalls der Meinung, dass diese Art der Tests mich davor schützt, Komponenten ungewollt zu „zerstören“. Diese naive Weltsicht hielt sich nicht lange, denn der Auszug aus dem DOM, stellt eben nicht sicher, dass die Komponente wie gewünscht angezeigt wird. Hier kommen Cypress Tests wesentlich näher an das Ergebnis ran.

Die Quintessenz ist, Snapshot-Tests sichern mir zu, dass das erzeugte „HTML“ mit dem übereinstimmt, was zuletzt eingecheckt wurde – jedoch sichert es mir nicht zu, dass der Benutzer meiner Applikation die Komponente korrekt sieht, geschweige denn sie sich korrekt verhält.

Somit wird ein falsches Sicherheitsbewusstsein bei den jeweiligen Entwickler*innen erzeugt, welches drastische Folgen haben kann.

3. Alle Entwickler*innen verstehen und ändern Snapshots mit Bedacht

Wir Devs möchten schnell Feedback haben, ob unsere Änderungen grün (also OK) oder rot (schlecht) sind. Dies erreichen wir mit Unit-Tests, somit können wir testgetrieben entwickeln oder kleine und größere Änderungen vornehmen ohne unsere Kund*innen zu verärgern in dem wir etwas kaputt machen.

Da aber Snapshot-Tests zwangsläufig rot sind, wenn Details geändert werden, können diese schnell ohne genaueres zusehen gepushed werden. Zumal das Übernehmen der Änderungen so einfach wie ein

jest --updateSnapshot

ist. Das kann zu kolossalen „F** ups“ führen. Das bedeutet auch, Snapshots können schnell unübersichtlich werden was solch ein Vorgehen ebenfalls begünstigt oder aber es werden die Ausmaße nicht bedacht was ebenfalls schlimm sein kann.

Die meisten nehmen die Snapshots auch als „Git Log“ wahr, was auch nicht verwerflich ist, denn die Komponenten werden als DOM „Kopie“ ins Repository eingecheckt. Dies wiederum spiegelt die letzte Änderung wieder.

Fazit

Es hat sicherlich einen Grund warum ebenfalls von Facebook die „react-testing-library“ empfohlen wird. Es geht darum die Komponenten zu testen und nicht deren Implementierung.

Spart euch den Schmerz, den schon viele vor euch durchgemacht haben – es gibt bessere Mittel als Snapshot-Tests (auch wenn es sicherlich valide und sinnvolle Anwendungszwecke dafür gibt).

Da ich mittlerweile in viele große Projekte involviert war, kann ich euch nur herzlichst davon abraten Snapshot-Tests zu verwenden. Wenn ihr es bis hierher geschafft habt, würde mich aber auch eure Meinung dazu interessieren. Lasst gerne einen Kommentar da!

2110cookie-checkWie wertvoll sind Snapshot-Tests?

Kommentar verfassen