Wie kann ich meinen REST-Webservice einem Unit-Test unterziehen?

16

Ich bin neu im Unit-Testen. Ich habe eine REST-Webmethode, die nur DB aufruft und ein DTO auffüllt. Pseudocode ist

public object GetCustomer(int id)
{
  CustomerDTO objCust = //get from DB
  return objCust;
}

Mein Zweifel ist, wie man Tests für diese Methoden schreibt und welche Art von Tests (Integration / Unit) einbezogen werden sollen. Und für Unit-Tests muss es die DB treffen. Wenn dies der Fall ist und ich eine Kunden-ID übergebe und nur wenige Aussagen mache, können sich die Daten möglicherweise ändern und zu Fehlern führen.

Ich glaube, hier fehlt mir etwas, um diese Konzepte zu verstehen.

Sonnig
quelle
5
In dem Code, den Sie gepostet haben, sind die zu testenden Dinge: (1) Können Sie GetCustomer mit einem int als Parameter aufrufen. (2) Gibt es ein CustomerDTO-Objekt zurück? (3) Ist das Objekt wie erwartet aus der Datenbank ausgefüllt? (4) Tritt ein erwartetes Verhalten auf, wenn es mit einem int aufgerufen wird, das keinem gültigen Kunden entspricht? Nichts davon hat mit REST zu tun. Wenn Sie bereit sind, den Code zu schreiben, der auf RESTful-Anforderungen reagiert, schreiben Sie Tests dafür.
DavidO
@DavidO: "Ist das Objekt wie erwartet aus der Datenbank ausgefüllt?" ist definitiv kein Komponententest (in Bezug auf den OP-Code). Das ist ein Integrationstest.
Flater
Ja du hast Recht. Wenn ich zurückgehen und den Kommentar ändern könnte, um zu erwähnen, dass Sie in einem Integrationstest die DB-Komponente verifizieren und andernfalls verspotten würden, würde ich diese Änderung vornehmen, aber das Bearbeitungsfenster für Kommentare wäre 5 Minuten lang, und der Kommentar wäre sechs vor Jahren. :)
DavidO

Antworten:

18

Während des Komponententests wird nicht erwartet, dass Sie mit einer Datenbank testen, oder zumindest nicht mit einer Datenbank, die Sie nicht für den Komponententest vorbereitet haben. Das Testen mit einer Datenbank und als solches das gleichzeitige Testen verschiedener Ebenen Ihrer Anwendung wird im Allgemeinen als Integrationstest angesehen . Bei Unit-Tests sollten Sie nur testen, was Ihre Methode tut, was sie in Abhängigkeit von verschiedenen Parametern zurückgibt und wann (oder nicht) sie fehlschlagen sollte.

Es wird sehr erwartet, dass Sie in Ihrer Methode X- Methoden aus anderen Klassen aufrufen. Sie testen diese X- Methoden nicht. Sie müssen sich also nur über diese Methoden lustig machen .

Ich nehme an, Sie schreiben Ihren Code in Java. In diesem Fall verfügen Sie über großartige Spott-Frameworks wie Mockito, die für Sie hilfreich sein können. Egal, ob Sie ein spöttisches Framework verwenden oder nicht, ich sage nur, es spart Ihnen viel Zeit, und das, was ich zumindest erwähnte, ist wirklich nicht kompliziert.

Wenn Sie nur einen eigenen Versuch schreiben möchten, nehmen wir an, Sie haben die folgende CustomerRepositoryKlasse:

public class CustomerRepository {
 public CustomerDTO getCustomer(int id) {
   ...
 }
}

Sie können Ihre eigene verspottete und schmutzige CustomerRepositoryKlasse folgendermaßen schreiben :

public class MockedCustomerRepository extends CustomerRepository {
 public boolean bThrowDatabaseException;
 public boolean bReturnNull;
 public boolean bReturnCustomerWrongId;
 public boolean bReturnCustomerWithId;
 public CustomerDTO getCustomer(int id) {
  if(bThrowDatabaseException) { 
    throw new DatabaseException("xxx"); 
  } else if(bReturnNull) { 
    return null; 
  } else if(bReturnCustomerWrongId) { 
    throw new CustomerNotExistException(id);
  } else if(bReturnCustomerWithId) { 
    return new CustomerDTO(id); 
  }
 }
}

In Ihrem Testfall ersetzen Sie dann im Grunde Ihre "Standard" -Instanz von CustomerRepositorydurch eine verspottete Instanz, mit der Sie Ihre Methode auf verschiedene Ergebnisse testen können getCustomer:

public class CustomerRestTest {
  public void testGetCustomer_databaseFailure() {
    MockedCustomerRepository dto = new MockedCustomerRepository();
    dto.bThrowDataBaseException = true;
    yRestClass rest = new MyRestClass();
    rest.dto = dto;
    rest.getCustomer(0);
    // depending on what you do in your getCustomer method, you should check if you catched the exception, or let it pass, etc.. Make your assertions here

  public void testGetCustomer_customerNotExist() {
    // etc.
  }
}

Im Allgemeinen sollte jede Testmethode nur eines testen. Dies hilft, Ihre Tests klein zu halten und sich auf eine Aufgabe zu konzentrieren.

Ich werde es wiederholen :-) Das Schreiben einer ganzen verspotteten Klasse dauert einige Zeit, wie Sie sehen. Erwägen Sie die Verwendung eines spöttischen Frameworks. Je weniger Code geschrieben wird, desto weniger Fehler macht man , oder? Das Verspotten einer Methode, die eine Ausnahme auslöst oder einen bestimmten Wert für einen bestimmten Parameter zurückgibt, ist ein Kinderspiel und benötigt 2 oder 3 Zeilen (mindestens mit mockito).

Hoffe, das hilft beim Testen Ihrer REST-Methode.

Jalayn
quelle
4
Normalerweise haben Sie keine Logik in Ihren DTO-Klassen, insbesondere keine, die mit Ihrem Datenspeicher interagieren.
JustAnotherUserYouMayKnowOrNot
1
Es war nur ein Beispiel, aber Sie haben absolut Recht. Ich werde die Beispiele ändern, damit sie besser zur Theorie passen.
Jalayn