Dienstag, Mai 29, 2018

Links der Woche

  • Eine Sammlung der 75 besten(?) Blogs über das Testen von Software: abtstracta.us/blog/75-best-software-testing-blogs
  • Werden manuelle Tests benötigt? Eine Antwort versucht dieser Blog zu geben.
  • Und hier ein Beitrag zu dem Thema, wann ist Testautomatisierung sinnvoll.
  • Ein Post über das Löschen von automatisierten Test.
  • Wie ist mit nicht-deterministischen Tests umzugehen? Dieser Blog versucht das Thema zu beleuchten.
  • Google´s Guava ist mittlerweile ein alter Hut und mit Java 8 sind viele Ideen aus Guava mit ins JDK eingeflossen. Dennoch lohnt sich ein Blick. Beispiel: Ranges, Throwables, Graphs
  • Wiremock simuliert HTTP basierte APIs. Interessant ist die Wiremock API selber. Die Aufrufe für das Starten/Stoppen und Stubben der Methoden kann man bequem im Testcode integrieren oder man startet Wiremock als eigenständigen Service.
  • Zahlen-, Datums- oder Währungskonvertierungen in Javascript? Dann empfiehlt sich Globalize.
  • Ein Texteditor für das Web. Im Mittelpunkt der Funktionalität steht das gemeinsame, gleichzeitige Arbeiten an einem Dokument.
  • Fefes Blog. Kennt ihr schon, oder?
  • Brewcraft, die wahre Kunst Bier zu brauen. Hier gibt es alles für den Hobbybrauer. Mit einem interessanten Artikel über alkoholfreie Biere.
  • Das java.util.Optional lässt mich nicht in Ruhe. Auf der einen Seite bietet es neben #isPresent() nette Abkürzungen wie #ifPresent(), #orElse() oder #orElseThrows(). Auf der anderen Seite habe ich im Alltag das Gefühl, dass das Optional eine inflationäre Verwendung findet. Im www fand ich dazu die folgenden Artikel. Eine allgemeine Empfehlung lautet:
    • Never, ever, use null for an Optional variable or return value.
    • Never use Optional.get() unless you can prove that the Optional is present.
    • Prefer alternative APIs over Optional.isPresent() and Optional.get().
    • It’s generally a bad idea to create an Optional for the specific purpose of chaining methods from it to get a value.
    • If an Optional chain has a nested Optional chain, or has an intermediate result of Optional, it’s probably too complex.
    • Avoid using Optional in fields, method parameters, and collections.On a related note, I thought of another rule after I presented the session: Don’t use an Optional to wrap any collection type (List, Set, Map). Instead, use an empty collection to represent the absence of values.

Dienstag, Mai 22, 2018

Hibernate und java.util.Date

In der Hibernate Welt geschehen manchmal unerklärliche Dinge. In diesem Fall war es der java.util.Date Typ einer Eigenschaft aus einer Hibernate Entity. Dieses Datumsfeld wurde für einen Vergleich mit einem anderen Datum herangezogen. Als Beispiel dient die Entity Person mit dem Datumsfeld #geburtstag. Die interessanten Dinge finden sich in (1) und (2). Bevor die Entity in der Datenbank angelegt wird, ist alles wie erwartet. Das java.util.Date ist ein java.util.Date. Der Vergleich liefert ebenfalls ein positives Ergebnis.

@Entity
@Table("PERSON")
public class Person {
    @Id
    @Column(name = "PERSON_ID")
    private Long personId;

    @Column(name = "NAME")
    private String name;

    @Column(name = "VORNAME")
    private String vorname;

    @Column(name = "GEBURTSTAG")
    private java.util.Date geburtstag;

    ...
}

final Date date = new DateTime(2018, 5, 22, 17, 0, 0).toDate();

Person person = new Person();
person.setGeburtstag(date);
person.setName("Name");
person.setVorname("Vorname");

// (1) Vergleich vor #save() und #refresh()
assertThat(person.getGeburtstag()).isInstanceOf(Date.class);
assertThat(person.getGeburtstag()).isNotInstanceOf(java.sql.Timestamp.class);
assertThat(person.getGeburtstag()).isEqualTo(date);

getSessionFactory().getCurrentSession().saveOrUpdate(person);
getSessionFactory().getCurrentSession().refresh(person);

// (2) Vergleich nach #save() und #refresh()
assertThat(person.getGeburtstag()).isInstanceOf(Date.class);
assertThat(person.getGeburtstag()).isInstanceOf(java.sql.Timestamp.class);
assertThat(person.getGeburtstag()).isNotEqualTo(date);
// IS NOT EQUAL, weil java.sql.Timestamp!
assertThat(now).isEqualTo(newRound.getDateTime());
// IS EQUAL! java.util.Date benutzt für den Vergleich long getTime()

Nach dem persistieren der Daten geschehen die bemerkenswerten Dinge. Aus dem java.util.Date wird ein java.sql.Timestamp. Das wäre nicht weiter tragisch, wenn nicht der Vergleich assertThat(person.getGeburtstag()).isNotEqualTo(now); positiv ausfallen würde. Was ist passiert? Mit dem refresh wurde die Entity Person neu aus der Datenbank gelesen, d.h. Hibernate liest per JDBC Verbindung die Daten aus der Datenbank. Für eine Timestamp Spalte lautet der entsprechende JDBC Typ java.sql.Timestamp, welcher von java.util.Date abgeleitet ist. In der #equals() Methode von java.sql.Timestamp findet sich der Hinweis:

true if the given Object is an instance of a Timestamp that is equal
to this Timestamp object; false otherwise

D.h. ein Vergleich von java.sql.Timestamp und java.util.Date ist immer false. Umgekehrt funktioniert der Vergleich: assertThat(now).isEqualTo(newRound.getDateTime());, da java.util.Date#equals() für den Vergleich auf das Ergebnis der Methode #getTime() zugreift. Das beste ist, man umgeht dieses Problem und verwendet gleich das java.time.LocalDateTime aus JDK 8 oder höher. Falls diese Option nicht besteht, empfiehlt sich für den Vergleich die #compare() Methode. java.sql.Timestamp implementiert #compare(Timestamp) und ein #compare(Date).

Donnerstag, Mai 17, 2018

Mockito Stubbing

Mockito gibt dem Entwickler zwei Möglichkeiten an die Hand, Methoden zu stubben. Variante 1, und vermutlich die beliebteste, ist die when/thenReturn Variante. Die Variante 2 doReturn/when dreht die Syntax um. Ein wesentlicher Unterschied zwischen den beiden Methoden ist die Typsicherheit der Variante 1.

when(mockOfClassXy.methodCall(anyParam())).thenReturn(anObject);

Der Typ von anObject muss dem Rückgabetyp der Methode #methodCall(...) entsprechen. Im Gegensatz zu der Variante 2

doReturn(anObject).when(mockOfClassXy).methodCall(anyParam());

kann anObject ein beliebiger Typ sein. Der Fehler wird erst zur Laufzeit entdeckt. Für das Stubben von void Methoden muss auf Variante 2 zurückgegriffen werden. Statt doReturn wird doNothing verwendet. Beispiel:

doNothing().when(mockOfClassA).voidMethodCall(anyParam());

Das stört bei strikter Verwendung von Variante 1 den Lesefluß. Teilweise gibt es hier die Empfehlung ganz auf Variante 1 zu verzichten und komplett auf Variante 2 umzusteigen. Wie gesagt, würde man dann auf die Typprüfung verzichten. Insbesondere bei ‘großen’ Projekten mit langen Testausführungszeiten wäre das vermutlich ein Problem.

Auf Stackoverflow finden sich zu dem Thema massig Einsendungen. Hier ein Beispiel:
Mockito when/thenReturn vs doReturn/when

Links der Woche

  • CSV Dateien verarbeiten mit Javascript? Vielleicht verrückt. Hier ist eine Lösung: papaparse
  • Auf Heise gibt es einen Kommentar zu den aktuellen Problemen mit EFail und der Aufregung, dass PGP kaputt sei: heise.de
  • Eine Javascript Bibliothek zum Zeichnen von Diagrammen. Die Diagramme versuchen möglichst handgemalt auszusehen. Das lässt das Ganze weniger steril wirken: Rough.js
  • Für C++ Programmierer ein Muss. Der CPP Core Guide von und mit Bjarne Stroustrup zu finden auf GitHub:
  • Eine Alternative zu Angular und anderen -eher schwergewichtigen- Frameworks. cujojs.com. Cujo orientiert sich wieder mehr an den Web-Standards und an den Möglichkeiten, die Javascript bietet.
  • Fear of the Dark. Interpretiert von den Mozart Heros: Fear of the Dark

AssertJ und java.util.List

AssertJ hat eine praktische Möglichkeit, Listen in JUnit Tests abzuprüfen. Insbesondere, wenn in der Liste komplexe Objekte abgelegt sind, s...