Parasoft C/C++test 2022.2 unterstützt das neue MISRA C:2012 Amendment 3 und eine Entwurfsversion von MISRA C++ 202x. Erfahren Sie mehr >>

Verspotten in Java: So automatisieren Sie einen Java-Komponententest, einschließlich Verspottung und Behauptungen

Von Brian McGlauflin

19. Juli 2018

6  min lesen

Was ist Spott in Java? Sie können einen Komponententest mit einem einzigen Klick automatisch generieren, einschließlich aller Verspottungen und Validierungen.

Gute Unit-Tests sind eine großartige Möglichkeit, um sicherzustellen, dass Ihr Code heute funktioniert und auch in Zukunft funktioniert. Eine umfassende Testsuite mit einer guten codebasierten und verhaltensbasierten Abdeckung kann einem Unternehmen viel Zeit und Kopfschmerzen ersparen. Und dennoch ist es nicht ungewöhnlich, Projekte zu sehen, in denen nicht genügend Tests geschrieben wurden. In der Tat haben einige Entwickler sogar vollständig gegen ihre Verwendung argumentiert.

Um mehr über Komponententests zu erfahren, besuchen Sie: parasoft.com/solutions/unit-testing/

Was macht einen guten Unit-Test aus?

Es gibt viele Gründe, warum Entwickler nicht genügend Komponententests schreiben. Einer der Hauptgründe ist die Zeit, die sie für den Bau und die Wartung benötigen, insbesondere bei großen, komplexen Projekten. In komplexen Projekten muss ein Komponententest häufig viele Objekte instanziieren und konfigurieren. Das Einrichten nimmt viel Zeit in Anspruch und kann den Test komplexer (oder komplexer) machen als den Code, den er selbst testet.

Schauen wir uns ein Beispiel in Java an:

Öffentlichkeit LoanResponse requestLoan (LoanRequest Leihantrag, Kreditstrategie und Dritten )
{     LoanResponse response = new LoanResponse();     response.setApproved(true);     if (loanRequest.getDownPayment().compareTo(loanRequest.getAvailableFunds()) > 0) {        response.setApproved(false);        response.setMessage("error.insufficient.funds.for.down.payment");        return response;     }     if (strategy.getQualifier(loanRequest) < strategy.getThreshold(adminManager)) {         response.setApproved(false);         response.setMessage(getErrorMessage());     }     return response; }

Hier haben wir eine Methode, die a verarbeitet Kreditanfrage, erzeugen a Kreditantwort. Beachten Sie das Kreditstrategie Argument, das verwendet wird, um die zu verarbeiten Kreditanfrage. Das Strategieobjekt kann komplex sein - es kann auf eine Datenbank oder ein externes System zugreifen oder a auslösen LaufzeitAusnahme. Um einen Test für zu schreiben Darlehen anfordern()Ich muss mir Sorgen machen, welche Art von Kreditstrategie Ich teste mit und ich muss wahrscheinlich meine Methode mit einer Vielzahl von testen Kreditstrategie Implementierungen und Kreditanfrage Konfigurationen.

Ein Unit Test fürDarlehen anfordern()könnte so aussehen:

@Test public void testRequestLoan() throws Throwable {    // Set up objects    DownPaymentLoanProcessor processor = new DownPaymentLoanProcessor();    LoanRequest loanRequest = LoanRequestFactory.create(1000, 100, 10000);    LoanStrategy strategy = new AvailableFundsLoanStrategy();    AdminManager adminManager = new AdminManagerImpl();    underTest.setAdminManager(adminManager);    Map<String, String> parameters = new HashMap<>();    parameters.put("loanProcessorThreshold", "20");    AdminDao adminDao = new InMemoryAdminDao(parameters);    adminManager.setAdminDao(adminDao);    // Call the method under test    LoanResponse response = processor.requestLoan(loanRequeststrategy);    // Assertions and other validations 

Wie Sie sehen können, gibt es einen ganzen Abschnitt meines Tests, in dem nur Objekte erstellt und Parameter konfiguriert werden. Es war nicht offensichtlich, das zu betrachten Darlehen anfordern() Methode, welche Objekte und Parameter eingerichtet werden müssen. Um dieses Beispiel zu erstellen, musste ich den Test ausführen, eine Konfiguration hinzufügen, dann erneut ausführen und den Vorgang immer wieder wiederholen. Ich musste zu viel Zeit damit verbringen, herauszufinden, wie man das konfiguriert Admin-Manager und Kreditstrategie anstatt mich auf meine Methode und das zu konzentrieren, was dort getestet werden musste. Und ich muss meinen Test noch erweitern, um mehr abzudecken Kreditanfrage Fälle, mehr Strategien und mehr Parameter für AdminDao.

Durch die Verwendung realer Objekte zum Testen überprüft mein Test außerdem mehr als nur das Verhalten von Darlehen anfordern() - Ich bin abhängig vom Verhalten von VerfügbareMittelDarlehenStrategie, AdminManagerImplund AdminDao damit mein Test läuft. Tatsächlich teste ich auch diese Klassen. In einigen Fällen ist dies wünschenswert, in anderen Fällen jedoch nicht. Wenn sich eine dieser anderen Klassen ändert, schlägt der Test möglicherweise fehl, obwohl das Verhalten von Darlehen anfordern() hat sich nicht geändert. Für diesen Test möchten wir die zu testende Klasse lieber von ihren Abhängigkeiten isolieren.

Was ist Spott in Java?

Eine Lösung für das Komplexitätsproblem besteht darin, diese komplexen Objekte zu verspotten. In diesem Beispiel verwende ich zunächst ein Modell für das Kreditstrategie Parameter:

@Prüfung

öffentliche Leere testRequestLoan () wirft Werfbar
    // Objekte einrichten 
    AnzahlungDarlehenProzessor Prozessor = erneuerbare DownPaymentLoanProcessor (); LoanRequest Leihantrag = LoanRequestFactory.create (1000, 100, 10000); LoanStrategy und Dritten  = Mockito.mock (LoanStrategy.Klasse); Mockito.when (und Dritten .getQualifier (any (LoanRequest.Klasse))). thenReturn (20.0d); Mockito.when (und Dritten .getThreshold (beliebig (AdminManager).Klasse))). thenReturn (20.0d);

    // Rufe die zu testende Methode auf
    Kreditantwort Antwort = process.requestLoan (Leihantragund Dritten );

    // Behauptungen und andere Validierungen
}

Schauen wir uns an, was hier passiert. Wir erstellen eine verspottete Instanz von Kreditstrategie Verwendung von Mockito.mock (). Da wissen wir das getQualifier () und getThreshold () Wird auf die Strategie aufgerufen, definieren wir die Rückgabewerte für diese Aufrufe mit Mockito.when (…) .thenReturn (). Für diesen Test ist es uns egal, was das ist Kreditanfrage Die Werte der Instanz sind und wir brauchen keine realen Admin-Manager mehr weil Admin-Manager wurde nur von der realen verwendet Kreditstrategie.

Außerdem, da wir keine echte verwenden KreditstrategieEs ist uns egal, was die konkreten Implementierungen von Kreditstrategie könnte tun. Wir müssen keine Testumgebungen, Abhängigkeiten oder komplexen Objekte einrichten. Wir konzentrieren uns auf das Testen Darlehen anfordern() - nicht Kreditstrategie or Admin-Manager. Der Code-Fluss der zu testenden Methode wird direkt vom Mock gesteuert.

Dieser Test ist mit Mockito viel einfacher zu schreiben, als wenn ich einen Komplex erstellen müsste Kreditstrategie Beispiel. Aber es gibt noch einige Herausforderungen:

  • Für komplexe Anwendungen erfordern Tests möglicherweise viele Verspottungen
  • Wenn Sie Mockito noch nicht kennen, müssen Sie dessen Syntax und Muster kennenlernen
  • Möglicherweise wissen Sie nicht, welche Methoden verspottet werden müssen
  • Wenn sich die Anwendung ändert, müssen auch die Tests (und Verspottungen) aktualisiert werden

Lösen von Mocking-Herausforderungen mit einem Java-Unit-Test-Generator

Wir haben Parasoft Jtest entwickelt, um die oben genannten Herausforderungen zu bewältigen. Das Unit-Testing-Modul Parasoft Jtest, eine Unternehmenslösung für Java-Tests, mit der Entwickler die Risiken der Java-Softwareentwicklung bewältigen können.

Auf der Seite der Komponententests hilft Ihnen Parasoft Jtest dabei, einige der schwierigsten Teile beim Erstellen und Verwalten von Komponententests mit Mocks zu automatisieren. Für das obige Beispiel kann automatisch ein Test für generiert werden Darlehen anfordern() mit einem einzigen Knopfdruck, einschließlich aller Verspottungen und Validierungen, die Sie im Beispieltest sehen.


Hier habe ich die Aktion "Normal" im Parasoft Jtest verwendet Unit-Test-Assistent Symbolleiste zum Generieren des folgenden Tests:

@Test public void testRequestLoan() throws Throwable {     // Given     DownPaymentLoanProcessor underTest = new DownPaymentLoanProcessor();     // When doppelt verfügbares Vermögen = 0.0d// UTA: Standardwert doppelt Anzahlung = 0.0d// UTA: Standardwert doppelt LoanAmount = 0.0d// UTA: Standardwert     LoanRequest loanRequest = LoanRequestFactory.create(availableFundsdownPaymentloanAmount);     LoanStrategy strategy = mockLoanStrategy();     LoanResponse result = underTest.requestLoan(loanRequeststrategy);    // Then    // assertNotNull(result); }

Alle Verspottungen für diesen Test erfolgen in einer Hilfsmethode:

private statische LoanStrategy mockLoanStrategy () wirft Throwable {LoanStrategy und Dritten  = mock (LoanStrategy.Klasse);
    doppelt getQualifierResult = 0.0d; // UTA: Standardwert
    wann(und Dritten .getQualifier (any (LoanRequest.Klasse))). thenReturn (getQualifierResult);

    doppelt getThresholdResult = 0.0d; // UTA: Standardwert
    wann(und Dritten .getThreshold (beliebig (AdminManager).Klasse))). thenReturn (getThresholdResult);

    Rückkehr und Dritten ;; }}

Alle notwendigen Verspottungen sind für mich eingerichtet - Parasoft Jtest hat die Methodenaufrufe erkannt getQualifier () und getThreshold () und verspottete die Methoden. Sobald ich Werte in meinem Unit Test für konfiguriert habe verfügbares Vermögen, Anzahlungusw. ist der Test betriebsbereit (ich könnte auch einen parametrisierten Test für eine bessere Abdeckung generieren!). Beachten Sie auch, dass der Assistent anhand seiner Kommentare „UTA: Standardwert“ eine Anleitung gibt, welche Werte geändert werden sollen, um das Testen zu vereinfachen.

Dies spart viel Zeit beim Generieren von Tests, insbesondere wenn ich nicht weiß, was verspottet werden muss oder wie die Mockito-API verwendet wird.

Umgang mit Codeänderungen

Wenn sich die Anwendungslogik ändert, müssen sich häufig auch die Tests ändern. Wenn der Test gut geschrieben ist, sollte er fehlschlagen, wenn Sie den Code aktualisieren, ohne den Test zu aktualisieren. Die größte Herausforderung bei der Aktualisierung des Tests besteht häufig darin, zu verstehen, was aktualisiert werden muss und wie genau diese Aktualisierung durchgeführt werden muss. Wenn es viele Verspottungen und Werte gibt, kann es schwierig sein, die notwendigen Änderungen zu ermitteln.

Um dies zu veranschaulichen, nehmen wir einige Änderungen am zu testenden Code vor ::

Öffentlichkeit LoanResponse requestLoan (LoanRequest Leihantrag, Kreditstrategie und Dritten ) {... String Folge = und Dritten .bestätigen(Leihantrag);
    if (Folge != null &&!Folge.ist leer()) {
        Antwort.setApproved (falsch);
        Antwort.setMessage (Folge);
        Rückkehr Antwort;; } ...
    Rückkehr Antwort;; }}

Wir haben eine neue Methode hinzugefügt LoanStrategy - validate ()und rufen es jetzt von Darlehen anfordern(). Der Test muss möglicherweise aktualisiert werden, um anzugeben, was bestätigen() sollte zurückkehren.

Lassen Sie uns den generierten Test im Parasoft Jtest Unit Test Assistant ausführen, ohne ihn zu ändern:

Parasoft Jtest hat das festgestellt bestätigen() wurde auf den verspotteten gerufen Kreditstrategie Argument während meines Testlaufs. Da die Methode nicht für den Mock eingerichtet wurde, empfiehlt der Assistent, den Mock zu verspotten bestätigen() Methode. Die Schnellkorrekturaktion „Mock it“ aktualisiert den Test automatisch. Dies ist ein einfaches Beispiel - aber bei komplexem Code, bei dem es nicht einfach ist, das fehlende Modell zu finden, können wir durch die Empfehlung und die schnelle Lösung viel Zeit beim Debuggen sparen.

Nachdem ich den Test mit der Schnellkorrektur aktualisiert habe, kann ich das neue Modell sehen und den gewünschten Wert für einstellen validResult:

private statische LoanStrategy mockLoanStrategy () wirft Throwable {LoanStrategy und Dritten  = mock (LoanStrategy.Klasse); String validResult = ""// UTA: Standardwert
    wann(und Dritten .validate (any (LoanRequest.Klasse))). thenReturn (validResult);
    doppelt getQualifierResult = 20.0d; wann(und Dritten .getQualifier (any (LoanRequest.Klasse))). thenReturn (getQualifierResult);

    doppelt getThresholdResult = 20.0d; wann(und Dritten .getThreshold (beliebig (AdminManager).Klasse))). thenReturn (getThresholdResult);
    Rückkehr und Dritten ;; }}

Ich kann validateResult mit einem nicht leeren Wert konfigurieren, um den Anwendungsfall zu testen, in dem die Methode in den neuen Codeblock eingibt, oder ich kann einen leeren Wert (oder null) verwenden, um das Verhalten zu validieren, wenn der neue Block nicht eingegeben wird.

Analyse des Testflusses

Der Assistent bietet auch einige nützliche Tools zur Analyse des Testflusses. Hier ist zum Beispiel der Flussbaum für unseren Testlauf:

Der Parasoft Jtest Unit-Test-Assistent's Flow Tree, der Aufrufe anzeigt, die während der Testausführung getätigt wurden

Wenn der Test ausgeführt wurde, kann ich sehen, dass der Test ein neues Modell für erstellt hat Kreditstrategieund verspottete die bestätigen(), getQualifier ()und getThreshold () Methoden. Ich kann Methodenaufrufe auswählen und (in der Variablenansicht) sehen, welche Argumente an diesen Aufruf gesendet wurden und welcher Wert zurückgegeben wurde (oder Ausnahmen ausgelöst wurden). Beim Debuggen von Tests kann dies viel einfacher zu verwenden und zu verstehen sein als das Durchsuchen von Protokolldateien.

Zusammenfassung

So automatisieren Sie viele Aspekte des Unit-Tests. Mit Parasoft Jtest können Sie Unit-Tests mit weniger Zeit und Aufwand erstellen und so die Komplexität reduzieren, die mit dem Verspotten verbunden ist. Es enthält auch viele andere Empfehlungen zur Verbesserung vorhandener Tests auf der Grundlage von Laufzeitdaten und unterstützt parametrisierte Tests, Spring Application-Tests und PowerMock (zum Verspotten statischer Methoden und Konstruktoren). Sie können eine bekommen 7 Tage Testversion kostenlos Um es in Ihrer eigenen Umgebung zu überprüfen, klicken Sie unten:

Von Brian McGlauflin

Brian McGlauflin ist Softwareentwickler bei Parasoft und verfügt über Erfahrung in der Full-Stack-Entwicklung mit Spring und Android, API-Tests und Service-Virtualisierung. Derzeit konzentriert er sich auf automatisierte Softwaretests für Java-Anwendungen mit Parasoft Jtest.

Erhalten Sie die neuesten Nachrichten und Ressourcen zum Testen von Software sofort.