| 

.NET C# Java Javascript Exception

3
Neulich im Projekt:

@Service
public class MyService {
private List<String> listA;
private List<String> listB;

@PostConstruct
void init() { //initialisiere listA und listB }

public void do(boolean useA, boolean isSpecial) {
List<String> workList = useA ? listA : listB;

//dieser Teil wurde nachträglich hinzugefügt, ohne genau hinzusehen
if (isSpecial) {
workList.add("Sonderfall");
}

doItReally(workList);
}

private void doItReally(List<String> workList) {}
}

MyService ist eine Spring-Bean und damit ein Singleton. Die Methode do() hat ursprünglich eine von zwei im weiteren zu verwendenden Listen ausgewählt (und noch einiges anderes vorbereitet). Später hat dann jemand noch den Sonderfall eingefügt und dabei nicht gemerkt, daß er dabei die Felder des Service ändert und damit auch das Ergebnis aller weiteren Aufrufe der Service-Methode :-(

Mal abgesehen davon, daß es natürlich gut gewesen wäre, wenn listA und listB von vornherein immutable erzeugt worden wären (z.B. mit ImmutableList von Guava), wäre meine Frage: könnte ich so etwas auch durch kluges Unit-Test-Schreiben verhindern/aufdecken? Aber natürlich auf eine allgemeine Weise - wenn ich im Unit-Test nach dem Aufruf von do() explizit abfrage, ob listA und listB noch unverändert sind, sehe ich das konkrete Problem ja schon voraus. Mir geht es eher darum zu testen, ob alle Service-Methoden auch bei mehrmaliger Verwendung noch wie vorgesehen funktionieren. Könnte man z.B. alle Tests einer Testklasse zweimal laufen lassen, mit dem gleichen Testobjekt natürlich?

Im konkreten Fall war JUnit im Einsatz, aber das soll hier nicht im Vordergrund stehen. Wenn jemand weiß, wie das andere Testframeworks, auch für andere Plattformen (insbesondere .NET) lösen, würde mich das auch interessieren.

Update: Ich versuche nochmal herauszustellen, welcher Aspekt mir wichtig ist:
Wenn Objekte für mehrmalige Verwendung vorgesehen sind, möchte man natürlich, daß sie nicht nur beim ersten Aufruf das tun, was sie sollen, sondern auch noch bei allen folgenden. Ein typischer Unit-Test würde das Objekt erzeugen, einen Testfall darauf ausführen, das Ergebnis prüfen - und dann weiter mit Objekt neu anlegen... Das läßt den Aspekt der Mehrfachausführung außen vor. Mir geht es darum zu erfahren, wie ich das ändern könnte. Besonders wichtig erscheint mir das bei Objekten, die einen Zustand haben, mit dem die Methoden zwar arbeiten sollen, aber ohne ihn zu verändern. Nicht immer gelingt es, den Zustand immutable zu implementieren, und dann würde ich gerne per Unit-Test sicherstellen, daß was auch immer in Zukunft mit der Klasse noch angestellt wird, das in einer Weise passiert, die den inneren Zustand nicht antastet.
Das Code-Beispiel skizziert letztlich nur den konkreten Anlaß für diese Überlegung.
30.07.2014
Matthias Hlawatsch 13,2k 4 9
2 Antworten
1
In NUnit gibt es das RepeatAttribute.

RepeatAttribute is used on a test method to specify that it should be executed multiple times. If any repetition fails, the remaining ones are not run and a failure is reported.
30.07.2014
Floyd 14,6k 3 9
Danke, das ist zumindest eine neue Info für mich. Für das konkrete Szenario würde es leider nur helfen, wenn ich die Test-Methoden größer mache, als sie eigentlich sein sollten, also im konkreten Beispiel Aufrufe mit isSpecial = true und false in einer Test-Methode.
Ein RepeatAttribute für eine ganze Test-Suite wäre da besser...
Matthias Hlawatsch 01.08.2014
0
Ich bin ehrlich, Java ist nicht meine Domäne. Deine Frage habe ich wahrscheinlich nicht komplett verstanden. Ich kenn auch diese Spring Beans nur aus dem Studium (das ist ne Zeit her :-( ). Zum Testen an sich bzw. OO Design glaube ich aber, etwas beitragen zu können.

Die Methode do() hat meiner Meinung nach an sich schon mehrere Probleme, da ist der Test erstmal untergeordnet. Zwei bool Parameter ergeben vier verschiedene Kombinationen. Für mich wären das vier Implementierungen eines Interfaces mit einer do() Methode ohne Parameter. Ich nenne es den bool-Parameter-smell.
Aus Testsicht würde ich dann vier Klassen statt Kombinatorik einer Klasse testen. Damit sollte das Problem, sofern ich es richtig verstanden habe, by-design gar nicht auftreten.
01.08.2014
ffordermaier 8,4k 3 9
Du hast meine Frage tatsächlich nicht im Kern verstanden, deshalb habe ich sie um ein Update ergänzt.
Java und Spring sind hier nicht wichtig. Denk Dir einen als Singleton konfigurierten WCF-Service, der aufwendig und einmalig einen Zustand aus der Datenbank lädt, der in den Service-Methoden verwendet wird, von diesen aber nicht verändert werden darf - aber ohne, daß der Zustand tatsächlich immutable implementiert ist. Das Problem, die Gefahr, ist latent da, sobald ich den Service so als Singleton mit Zustand konstruiere. Kann ich a priori via Unit-Test verhindern, daß das Problem akut wird?
Matthias Hlawatsch 01.08.2014
Die do-Methode im Beispiel soll nur skizzieren, wie einfach man in die Falle tappen kann. Klar könnte man die anders bauen - die Gefahr zu erkennen und zu umgehen, ist immer eine gute Idee. Aber Unit-Tests schreibe ich ja gerade für den Fall, daß jemand bei einer späteren Änderung etwas übersieht, was er hätte beachten sollen. (Der Service sah ja nicht von Anfang an so aus. Vielleicht gab es am Anfang sogar nur listA und eine do-Methode ohne Parameter - aber selbst da war die Gefahr schon da.)
Matthias Hlawatsch 01.08.2014

Stelle deine Unit-testing-Frage jetzt!