FIO® SYSTEMS AG




      Unit Tests und
Test Driven Development
       in der Praxis
       – alles grün?
FIO® SYSTEMS AG
Die Herausforderung
FIO® SYSTEMS AG
                      Unit Tests

• Testen automatisiert kleine, isolierte Einheiten (Units)
  eines Programms
• Stellen sicher, dass diese Units bestimmte Erwartungen
  erfüllen
FIO® SYSTEMS AG
                                           Ein Unit Test
[TestFixture]
public class AccountTest
{
    private Account firstAccount = new Account();
    private Account secondAccount = new Account();


    [TestFixtureSetUp]
    public void SetUp()
    {
        firstAccount.Transfer(secondAccount, 100);
    }


    [Test]
    public void TransferTest()
    {
        Assert.AreEqual(100, secondAccount.Balance);
    }
}
FIO® SYSTEMS AG
Funktionen von Unit Test Frameworks
• Annotationen zum Kennzeichnen der Testklasse (NUnit:
  [TestFixture], JUnit / TestNG: keine erforderlich)
• Annotationen zum Kennzeichnen von SetUp / TearDown
  (NUnit: [TestFixtureSetUp] / [SetUp],
  [TestFixtureTearDown] / [TearDown], JUnit / TestNG:
  @Before, @After, @BeforeClass, @BeforeMethod, …)
• Kennzeichnung der eigentlichen Tests (NUnit: [Test],
  JUnit / TestNG: @Test)
FIO® SYSTEMS AG
Funktionen von Unit Test Frameworks
• Assert Statements zum Definieren von Bedingungen
  (NUnit: Assert.AreEqual, JUnit / TestNG: assertsEquals)
• Annotationen zum Kennzeichnen von erwarteten
  Exceptions: NUnit:
  [Test][ExpectedException(typeof(ArithmeticException))],
  JUnit / TestNG: @Test(expected(Exceptions) =
  ArithmeticException.class)
FIO® SYSTEMS AG
            Bedingungen an Unit Tests
from „Working effectively with legacy code“ by Michael Feathers:

„A test is not a unit test if:
1. It talks to a database.
2. It communicates across a network.
3. It touches the file system.
4. You have to do special things to your environment to run
   it.“

Weitere: schnell, wiederholbar, verständlich, unabhängig
FIO® SYSTEMS AG
          Was bringen Unit Tests?

• Sicherheit
• Dokumentation
• Automatische Tests / Continuous Integration
• Geschwindigkeit (mittel- / langfristig)


• Aber: hohe Einarbeitungszeit, Zeitaufwand für Tests
FIO® SYSTEMS AG
         Unit Test nach dem Code
• …werden oft nicht geschrieben
• …testen nur das, was der Code hergibt
• …prüfen meist nur einen Teil der Funktionalität
• …sind oft schwer zu schreiben, da der Code schlecht
  testbar ist

Die Lösung: Test Driven Development
FIO® SYSTEMS AG
   Test Driven Development (TDD)
• RED: fehlschlagenden Test schreiben
• GREEN: nur soviel Code schreiben, um den Test grün zu
  machen
• REFACTOR: den Code aufräumen
FIO® SYSTEMS AG
   Test Driven Development (TDD)
• Praxis
FIO® SYSTEMS AG
              Kriterien für gute Tests
Gute Tests:
• Stellen sicher, dass erwartete Ergebnisse geliefert
  werden
• Testen Extrembedingungen / Fehlerzustände
• Testen Performance bei kritischen Funktionen
• Decken möglichst 100% des Codes ab
FIO® SYSTEMS AG
Codeabdeckung
FIO® SYSTEMS AG
          Weitere Schwierigkeiten
• Wie lässt sich eine solche Methode sinnvoll testen:

public class AccountController
{
    ...
    public void Save()
    {
        Account account = accountService.GetById(accountId);
        // ToDo: fill account with values from mask
        accountService.Save(account);
    }
}
FIO® SYSTEMS AG
 Die Lösung: Dependency-Injection
• Interface statt konkreter Implementierung verwenden
• Implementierung zugänglich machen durch z.B.:
  • Übergabe im Konstruktor
  • Übergabe im Funktionsaufruf
  • Setter
  • Service-Locator
  • DI-Framework
FIO® SYSTEMS AG
    Verwendung eines DI-Frameworks
ObjectFactory.Initialize(...);

public class AccountController
{
    private IAccountService service =
                   ObjectFactory.GetInstance<IAccountService>();

     public void Save()
     {
         Account account = service.GetById(accountId);
         // ToDo: fill account with values from mask
         service.Save(account);
     }
}
FIO® SYSTEMS AG
                    Und dann?
• Der getesteten Methode / Klasse etwas vorgauckeln mit:
• Fakes (Implementierung nur für den Test)
• Stubs (Geben die Werte zurück, die für den Test
  gebraucht werden)
• Mocks (Objekte mit Erwartungen bzgl. übergebener
  Werte und aufgerufener Funktionen)
FIO® SYSTEMS AG
           Stub, Fake, Mock
• Praxis
FIO® SYSTEMS AG
Behaviour Driven Development (BDD)
FIO® SYSTEMS AG
Behaviour Driven Development (BDD)
• Ausgangspunkt der Tests ist ein Akzeptanzkriterium
• Daraus wird eine Spezifikation der Form „Name, When,
  Then“ oder „Given, When, Then“ erstellt
• Die Ausgabe der Testläufe soll menschenlesbar und für
  Tester, Fachanwender oder Kunden verständlich sein
• Der Testcode selbst soll leicht verständlich sein, um als
  „lebendige Dokumentation“ zu dienen
FIO® SYSTEMS AG
Behaviour Driven Development (BDD)
FIO® SYSTEMS AG
Behaviour Driven Development (BDD)
• Praxis
FIO® SYSTEMS AG
       Continuous Integration (CI)
• Der beste Tests nutzt nichts, wenn er nicht nach jeder
  Änderung ausgeführt wird
• Der beste Code nutzt nichts, wenn er nicht integrierbar ist
• Bei 2 oder mehr Entwicklern lässt sich beides nur
  automatisiert sicherstellen
• Des Weiteren muss es im Team eine Quelle der
  ultimativen Wahrheit geben
FIO® SYSTEMS AG
       Continuous Integration (CI)
• Zentrales Code Repository
• Zentraler automatisierter Build nach jedem Commit
• Zentrale automatisierte Tests (evtl. nach Schedule)
• Info an das ganze Team bei Fehlern in Build oder in Tests
FIO® SYSTEMS AG
Continuous Integration (CI)
FIO® SYSTEMS AG
                          Die Aufgabe
Als praktisches Beispiel soll im Rahmen dieser Aufgabe eine Funktion zum
Berechnen von Zinsen nach der Methode 30/360 erarbeitet werden.

Voraussetzungen:

   Technisch: Die eingesetzte Programmiersprache sowie das verwendete Test-
   Framework können frei gewählt werden.

   Fachlich: Es soll die für Spareinlagen übliche Zinsmethode 30/360
   angewendet werden, wobei der letzte Tag (Auszahlungstag) als zinsfrei zu
   behandeln ist.
FIO® SYSTEMS AG
                     Aufgabenstellung
• Erstellung Programm zur Zinsberechnung in Einzelarbeit, Zinsmethode 30/360

• Nutzer soll Anzahl von Buchungen eingeben können (Buchungsdatum, Betrag,
  Buchungstext) und zur Zinsberechnung Start- sowie Enddatum und Zinssatz
  festlegen

• Programm soll Zinstage und berechnete Zinsen ausgeben

• Die Funktion zur Zinsberechnung mit den oben beschriebenen
  Eingabeparametern ist testgetrieben zu entwickeln. Es ist dabei immer zuerst
  der Test zu schreiben, ehe weitere Funktionalität hinzugefügt wird.
FIO® SYSTEMS AG
                 Ergebnispräsentation
Bei der Präsentation des Arbeitsergebnisses soll auch auf folgende Aspekte
eingegangen werden:

 aus welchem Grund die verwendeten Technologien und Tools zum Einsatz
  kamen
 welche Tests erstellt wurden und welches Schema zur Benennung der Tests
  verwendet wurde
 welche Probleme das testgetriebene Vorgehen aufgeworfen hat und wie sie
  ggf. gelöst werden konnten
FIO® SYSTEMS AG




Fragen?
FIO® SYSTEMS AG




Vielen Dank und viel Erfolg!
FIO® SYSTEMS AG



  Spätere Fragen bitte einfach
           per E-Mail
  (siehe Veranstaltungswebsite)
            stellen!


www.fio.de

Ringvorlesung ITmitte.de : Vortrag der FIO SYSTEMS AG über Unit Tests und TDD

  • 1.
    FIO® SYSTEMS AG Unit Tests und Test Driven Development in der Praxis – alles grün?
  • 2.
    FIO® SYSTEMS AG DieHerausforderung
  • 3.
    FIO® SYSTEMS AG Unit Tests • Testen automatisiert kleine, isolierte Einheiten (Units) eines Programms • Stellen sicher, dass diese Units bestimmte Erwartungen erfüllen
  • 4.
    FIO® SYSTEMS AG Ein Unit Test [TestFixture] public class AccountTest { private Account firstAccount = new Account(); private Account secondAccount = new Account(); [TestFixtureSetUp] public void SetUp() { firstAccount.Transfer(secondAccount, 100); } [Test] public void TransferTest() { Assert.AreEqual(100, secondAccount.Balance); } }
  • 5.
    FIO® SYSTEMS AG Funktionenvon Unit Test Frameworks • Annotationen zum Kennzeichnen der Testklasse (NUnit: [TestFixture], JUnit / TestNG: keine erforderlich) • Annotationen zum Kennzeichnen von SetUp / TearDown (NUnit: [TestFixtureSetUp] / [SetUp], [TestFixtureTearDown] / [TearDown], JUnit / TestNG: @Before, @After, @BeforeClass, @BeforeMethod, …) • Kennzeichnung der eigentlichen Tests (NUnit: [Test], JUnit / TestNG: @Test)
  • 6.
    FIO® SYSTEMS AG Funktionenvon Unit Test Frameworks • Assert Statements zum Definieren von Bedingungen (NUnit: Assert.AreEqual, JUnit / TestNG: assertsEquals) • Annotationen zum Kennzeichnen von erwarteten Exceptions: NUnit: [Test][ExpectedException(typeof(ArithmeticException))], JUnit / TestNG: @Test(expected(Exceptions) = ArithmeticException.class)
  • 7.
    FIO® SYSTEMS AG Bedingungen an Unit Tests from „Working effectively with legacy code“ by Michael Feathers: „A test is not a unit test if: 1. It talks to a database. 2. It communicates across a network. 3. It touches the file system. 4. You have to do special things to your environment to run it.“ Weitere: schnell, wiederholbar, verständlich, unabhängig
  • 8.
    FIO® SYSTEMS AG Was bringen Unit Tests? • Sicherheit • Dokumentation • Automatische Tests / Continuous Integration • Geschwindigkeit (mittel- / langfristig) • Aber: hohe Einarbeitungszeit, Zeitaufwand für Tests
  • 9.
    FIO® SYSTEMS AG Unit Test nach dem Code • …werden oft nicht geschrieben • …testen nur das, was der Code hergibt • …prüfen meist nur einen Teil der Funktionalität • …sind oft schwer zu schreiben, da der Code schlecht testbar ist Die Lösung: Test Driven Development
  • 10.
    FIO® SYSTEMS AG Test Driven Development (TDD) • RED: fehlschlagenden Test schreiben • GREEN: nur soviel Code schreiben, um den Test grün zu machen • REFACTOR: den Code aufräumen
  • 11.
    FIO® SYSTEMS AG Test Driven Development (TDD) • Praxis
  • 12.
    FIO® SYSTEMS AG Kriterien für gute Tests Gute Tests: • Stellen sicher, dass erwartete Ergebnisse geliefert werden • Testen Extrembedingungen / Fehlerzustände • Testen Performance bei kritischen Funktionen • Decken möglichst 100% des Codes ab
  • 13.
  • 14.
    FIO® SYSTEMS AG Weitere Schwierigkeiten • Wie lässt sich eine solche Methode sinnvoll testen: public class AccountController { ... public void Save() { Account account = accountService.GetById(accountId); // ToDo: fill account with values from mask accountService.Save(account); } }
  • 15.
    FIO® SYSTEMS AG Die Lösung: Dependency-Injection • Interface statt konkreter Implementierung verwenden • Implementierung zugänglich machen durch z.B.: • Übergabe im Konstruktor • Übergabe im Funktionsaufruf • Setter • Service-Locator • DI-Framework
  • 16.
    FIO® SYSTEMS AG Verwendung eines DI-Frameworks ObjectFactory.Initialize(...); public class AccountController { private IAccountService service = ObjectFactory.GetInstance<IAccountService>(); public void Save() { Account account = service.GetById(accountId); // ToDo: fill account with values from mask service.Save(account); } }
  • 17.
    FIO® SYSTEMS AG Und dann? • Der getesteten Methode / Klasse etwas vorgauckeln mit: • Fakes (Implementierung nur für den Test) • Stubs (Geben die Werte zurück, die für den Test gebraucht werden) • Mocks (Objekte mit Erwartungen bzgl. übergebener Werte und aufgerufener Funktionen)
  • 18.
    FIO® SYSTEMS AG Stub, Fake, Mock • Praxis
  • 19.
    FIO® SYSTEMS AG BehaviourDriven Development (BDD)
  • 20.
    FIO® SYSTEMS AG BehaviourDriven Development (BDD) • Ausgangspunkt der Tests ist ein Akzeptanzkriterium • Daraus wird eine Spezifikation der Form „Name, When, Then“ oder „Given, When, Then“ erstellt • Die Ausgabe der Testläufe soll menschenlesbar und für Tester, Fachanwender oder Kunden verständlich sein • Der Testcode selbst soll leicht verständlich sein, um als „lebendige Dokumentation“ zu dienen
  • 21.
    FIO® SYSTEMS AG BehaviourDriven Development (BDD)
  • 22.
    FIO® SYSTEMS AG BehaviourDriven Development (BDD) • Praxis
  • 23.
    FIO® SYSTEMS AG Continuous Integration (CI) • Der beste Tests nutzt nichts, wenn er nicht nach jeder Änderung ausgeführt wird • Der beste Code nutzt nichts, wenn er nicht integrierbar ist • Bei 2 oder mehr Entwicklern lässt sich beides nur automatisiert sicherstellen • Des Weiteren muss es im Team eine Quelle der ultimativen Wahrheit geben
  • 24.
    FIO® SYSTEMS AG Continuous Integration (CI) • Zentrales Code Repository • Zentraler automatisierter Build nach jedem Commit • Zentrale automatisierte Tests (evtl. nach Schedule) • Info an das ganze Team bei Fehlern in Build oder in Tests
  • 25.
  • 26.
    FIO® SYSTEMS AG Die Aufgabe Als praktisches Beispiel soll im Rahmen dieser Aufgabe eine Funktion zum Berechnen von Zinsen nach der Methode 30/360 erarbeitet werden. Voraussetzungen: Technisch: Die eingesetzte Programmiersprache sowie das verwendete Test- Framework können frei gewählt werden. Fachlich: Es soll die für Spareinlagen übliche Zinsmethode 30/360 angewendet werden, wobei der letzte Tag (Auszahlungstag) als zinsfrei zu behandeln ist.
  • 27.
    FIO® SYSTEMS AG Aufgabenstellung • Erstellung Programm zur Zinsberechnung in Einzelarbeit, Zinsmethode 30/360 • Nutzer soll Anzahl von Buchungen eingeben können (Buchungsdatum, Betrag, Buchungstext) und zur Zinsberechnung Start- sowie Enddatum und Zinssatz festlegen • Programm soll Zinstage und berechnete Zinsen ausgeben • Die Funktion zur Zinsberechnung mit den oben beschriebenen Eingabeparametern ist testgetrieben zu entwickeln. Es ist dabei immer zuerst der Test zu schreiben, ehe weitere Funktionalität hinzugefügt wird.
  • 28.
    FIO® SYSTEMS AG Ergebnispräsentation Bei der Präsentation des Arbeitsergebnisses soll auch auf folgende Aspekte eingegangen werden:  aus welchem Grund die verwendeten Technologien und Tools zum Einsatz kamen  welche Tests erstellt wurden und welches Schema zur Benennung der Tests verwendet wurde  welche Probleme das testgetriebene Vorgehen aufgeworfen hat und wie sie ggf. gelöst werden konnten
  • 29.
  • 30.
    FIO® SYSTEMS AG VielenDank und viel Erfolg!
  • 31.
    FIO® SYSTEMS AG Spätere Fragen bitte einfach per E-Mail (siehe Veranstaltungswebsite) stellen! www.fio.de