2017-06-05 2 views
1

Ich habe eine Funktion, die eine Modellklasse überprüft, in der jedes Mitglied der Klasse im Falle eines Strings nicht null oder nicht leer sein muss. so etwas wie diesesWie testet man eine Funktion mit N verschiedenen Pfaden?

Die Logik für diese is_complete Funktion ist:

def is_complete(profile): 
    if profile.first_name in (None, ''): 
     return False 
    elif profile.last_name in (None, ''): 
     return False 
    elif profile.dob is None: 
     return False 
    . 
    . 
    .# and checks so on for all members of the profile instance 
    . 
    . 

    return True 

Meine Frage, da die Anzahl der möglichen Pfade der Ausführung recht groß nehmen ist und erhöht sich proportional zu der Anzahl der Elementvariablen von profile zu geprüft werden, wie schreibt man zuverlässig Tests für alle möglichen Pfade?

Gerade jetzt, ich habe zwei einfache Testfälle:

  1. wo nur einige der Mitglieder festgelegt und überprüft assertFalse(is_complete(foo))
  2. wo alle die Mitglieder festgelegt und überprüft assertTrue(is_complete(foo))

Aber ich habe das Gefühl, dass dies nicht genug sein kann.

+1

Beim Komponententest müssen Sie nicht unbedingt jeden Pfad testen. Mit vielen Funktionen ist das nicht einmal möglich oder praktisch. Sie wollen einfach genug testen. Wenn eine Funktion komplex ist, ist dies wahrscheinlich ein Zeichen dafür, dass sie in kleinere Funktionen unterteilt werden sollte. – ThomasW

+0

Sie sollten Ihr Klassendesign ernsthaft überdenken. Im Idealfall sollte es nicht möglich sein, teilweise initialisierte Objekte zu erstellen. Konstrukteure sollten sich darum kümmern. Wenn einige der Daten, die Sie für die Initialisierung Ihrer Klasse benötigen, zum Zeitpunkt der Erstellung nicht verfügbar sind, versuchen Sie, sie in eine andere Klasse zu extrahieren. –

+0

@FrankPuffer Eine Instanz mit ihren Mitgliedern als leere Strings oder Nullen wird nicht als _partial initialized_ betrachtet, da sie einen gültigen Zustand darstellt, in dem die Instanz sein kann. Es könnte ein Formular darstellen, dessen Felder der Benutzer gerne leer gelassen hat. –

Antwort

1

Ich bin mir nicht sicher, was Sie meinen, indem Sie MxN Pfade haben. Im aufgegebenen Code haben Sie so viele Pfade wie Felder + 1.

Erstellen Sie eine Hilfsmethode, die eine profile erstellt, die vollständig ist und is_complete übergibt.

Fügen Sie eine Testmethode hinzu, um zu überprüfen, is_complete(profile) ist True für die vollständige profile.

In einem Testverfahren für jedes Feld, mit den folgenden Schritten:

  • Rufen Sie die Hilfsmethode ein komplettes Profil erstellen, die wir kennen würde is_complete
  • Brechen Sie das Feld unter Test
  • Überprüfen passieren dass is_complete kehrt False

Sie werden so viele Testmethoden wie Felder + 1.

Btw, statt dies:

if profile.first_name in (None, ''): 

können Sie Schriftsteller einfacher:

if not profile.first_name: 
+0

Sie haben Recht. Das sind nur 'n' Pfade. Tut mir leid, ich werde den Titel korrigieren. –

1

Sie können dies testen mit Randomisierung:

  • eine Funktion schreiben, die erstellt ein zufälliges Profil-Objekt mit allen Feldern gefüllt (könnte zufällig sein, aber gültig).
  • Ändern Sie zufällig ein oder mehrere Felder in None oder leer.
  • Übergeben Sie das Objekt an die Funktion is_complete().

Ich kann dies nur in Java mit Qala Datagen zeigen. Ich nehme an, Sie in den negativen Pfade interessiert sind, so kann es wie folgt aussehen:

@Test void profileIsNotComplete_ifAtLeastOneFieldIsBlank() { 
    Profile p = Profile.random(); 
    callOneOrMore(
     () -> profile.setName(nullOrEmpty()), 
     () -> profile.setLastName(nullOrEmpty()), 
     ...); 
    assertFalse(profile.isComplete(); 
} 

Beachten Sie, dass dieser Code tatsächlich mehr Tests - auch die Kombination der Felder überprüft auf null/leer. Wenn es in Python keine solchen Bibliotheken gibt, können Sie einige Hilfsmethoden für sich selbst schreiben.

NB: Es wird nur ein Pfad pro Ausführung getestet. Sie können es viele Male (tausend?) Ausführen, um sicherzustellen, dass alle Wege bestehen. Dann kannst du es in CI nur einmal ausführen, wenn dies keine unternehmenskritische Funktionalität ist und du hast keine Angst, dass es oft kaputt geht.

Andernfalls, wenn Sie wirklich diese bedeckt 100% für jeden Aufruf sein wollen, können Sie einige der guten Praktiken verletzen und nur in einem all diese Tests kombinieren (sonst gehen zu viele Tests sein, die das Lesen erschweren sie):

@Test void profileIsNotComplete_ifOneFieldIsBlank() { 
    assertFalse(Profile.random().setName(null).isComplete()); 
    assertFalse(Profile.random().setName("").isComplete()); 

    assertFalse(Profile.random().setLastName(null).isComplete()); 
    assertFalse(Profile.random().setLastName("").isComplete()); 
    ... 
} 

Das testet Kombinationen zwar nicht, aber Sie können beide Ansätze kombinieren. Der positive Fall ist sehr einfach in beiden Ansätzen:

@Test void profileIsComplete_ifAllFieldsAreFilled() { 
    assertTrue(Profile.random()); 
} 

Mehr Informationen zu randomisierten Tests sind here.

Verwandte Themen