Ich habe vor nicht allzu langer Zeit hier bereits darauf hingewiesen, dass vieles, das aktuell in riesigen Frameworks vermeintlich erfunden wurde und wird bereits (seit langem) Teil von Java SE ist.
Will man Tests - speziell Unit-Tests - in Java schreiben, bei denen man bestimmte Assertions auf die verronnene Zeit anwenden oder das Verhalten des eigenen Codes nach Ablauf einer ganz bestimmten Zeitspanne anwenden möchte, hat man das Problem, das heutigen Multicore-Architekturen inhärent ist: Man kann (ohne Echtzeitbetriebssystem) keine genauen Aussagen darüber machen, wie lange ein bestimmtes Stück Code für seine Abarbeitung benötigt.
Dann hat man in den oben beschriebenen Szenarien nur die Möglichkeit, relativ weite Grenzen für die Zeiten zu setzen, innerhalb derer der jeweilige Test noch als verifiziert gelten soll. Andererseits wird in der heutigen Softwareentwicklung der Code nicht nur einmal gebaut - in einer perfekten Welt sollte ein Build-Server existieren, der jeden Push auf bestimmte Branches mit einem Sanity-Check-Build beantwortet. Auf diesem Buildserver können aber ganz andere Ressourcenvoraussetzungen bestehen, als auf Entwicklerrechnern, was dazu führen kann, dass solche wie die beschriebenen Tests wieder reihenweise durchfallen.
Früher konnte man in Tests noch etwas erreichen, indem man statische Methoden zur Bestimmung der aktuellen Zeit gemockt hat. Heute gibt es einen eleganteren Weg: Man legt - zum Beispiel über entsprechende Architekturregeln, die mit korrespondierenden Tests automatisch überprüft werden - fest, dass nur noch die Methoden im Paket java.time für jegliche Operationen zur Bestimmung von Zeitpunkten benutzt werden. Diese Methoden akzeptieren alle einen (optionalen) Parameter vom Typ java.time.Clock - und die hierfür verwendete Instanz wird dann nicht direkt erzeugt, sondern von einem Dienst erfragt. In Tests kann man dann einen anderen Dienst benutzen, der eine MutableClock zurückliefert, deren Zeitwert sich beliebig manipulieren lässt. So arbeit zu testender Code immer mit der korrekten und wiederholt derselben Zeit.
Dieses System habe ich selber ausprobiert und dabei gleich noch eine Verbesserung vorgeschlagen: Normalerweise lassen sich BeanContext-Services ja nur von Beans Nutzen, die im gleichen BeanContext registriert sind, wie die Services. Das lässt sich durch die Verwendung zum Beispiel des folgenden Ansatzes aushebeln:
import java.beans.beancontext.BeanContextChildSupport;
import java.beans.beancontext.BeanContextServices;
import java.beans.beancontext.BeanContextServicesSupport;
import java.util.TooManyListenersException;
/**
* Usable for testing. For example:
* <pre>
* MutableClock mc=MutableClock.of(Instant.ofEpochMilli(1000000000), ZoneId.systemDefault());
* GlobalContext.getContextServices().addService(ClockSource.class,new ClockSourceServiceProvider(mc));
* ClockSource clockSource= GlobalContext.getService(ClockSource.class);
* System.out.println(Instant.now(clockSource.getClock()));
* mc.add(5, ChronoUnit.MINUTES);
* System.out.println(Instant.now(clockSource.getClock()));
* </pre>
*/
public class GlobalContext
{
private static final BeanContextServicesSupport context = new BeanContextServicesSupport(); // a bean context
private static final BeanContextChildSupport bean=new BeanContextChildSupport();
static
{
getContextServices().add(bean);
}
public static BeanContextServices getContextServices()
{
return context;
}
public static <T> T getService(Class<T> cls) throws TooManyListenersException
{
return (T)getContextServices().getService(bean,bean,cls,bean,bean);
}
}
Ein angenehmer Nebeneffekt dabei ist, dass die zurückgegebene Instanz durch die Generifizierung der Methode nicht - wie sonst im Umfeld des BeanContext allgemein üblich - erst noch gecastet werden muss, sondern direkt verwendet werden kann.
Ticketsysteme sind lebende Wesen
29.03.2020
Hier zunächst wieder eine Triggerwarnung: Dieser Artikel wird meine Meinung abbilden. es kann sein, dass sie dem einen oder anderen nicht gefällt - das ist mir aber egal. Und wenn hier irgendwelche Schneeflocken mitlesen, dann sind die selber schuld.
Weiterlesen...Android Basteln C und C++ Chaos Datenbanken Docker dWb+ ESP Wifi Garten Geo Go GUI Gui Hardware Java Jupyter JupyterBinder Komponenten Links Linux Markdown Markup Music Numerik OpenSource PKI-X.509-CA Präsentationen Python QBrowser Rants Raspi Revisited Security Software-Test sQLshell TeleGrafana Verschiedenes Video Virtualisierung Windows Upcoming...
Ich berichtete hier bereits über Experimente mit dem Clifford-Attractor, allerdings war ich noch Experimente unter geringfügig geänderten Parametern schuldig...
WeiterlesenEs wurde wieder einmal Zeit für ein neues Feature in meinem Static Site Generator mittels dessen ich ja auch meine Heimatseite im Zwischennetz gestalte und verwalte...
WeiterlesenEs kamen mehrere Faktoren zusammen: die Tatsache, dass ich nicht mehr ganz so kürzlich die 50 überschritten habe hatte ebenso darauf Einfluss wie das heutige trübe Wetter und auch der Fakt, dass ich bereits beinahe alle Wochenendpflichten erledigt habe. Der letzte Stein des Anstoßes war dann aber, dass sich heute zum 125. Mal der Geburtstag von Erich Fromm jährt.
WeiterlesenManche nennen es Blog, manche Web-Seite - ich schreibe hier hin und wieder über meine Erlebnisse, Rückschläge und Erleuchtungen bei meinen Hobbies.
Wer daran teilhaben und eventuell sogar davon profitieren möchte, muss damit leben, daß ich hin und wieder kleine Ausflüge in Bereiche mache, die nichts mit IT, Administration oder Softwareentwicklung zu tun haben.
Ich wünsche allen Lesern viel Spaß und hin und wieder einen kleinen AHA!-Effekt...
PS: Meine öffentlichen Codeberg-Repositories findet man hier.