521 Stimmen

Wie kann man abstrakte Klassen testen: mit Stubs erweitern?

Ich habe mich gefragt, wie man abstrakte Klassen und Klassen, die abstrakte Klassen erweitern, in einer Einheit testen kann.

Sollte ich die abstrakte Klasse testen, indem ich sie erweitere und die abstrakten Methoden ausblende, und dann alle konkreten Methoden testen? Dann nur die Methoden testen, die ich überschreibe, und die abstrakten Methoden in den Einheitstests für Objekte testen, die meine abstrakte Klasse erweitern?

Sollte ich einen abstrakten Testfall haben, der zum Testen der Methoden der abstrakten Klasse verwendet werden kann, und diese Klasse in meinem Testfall für Objekte erweitern, die die abstrakte Klasse erweitern?

Beachten Sie, dass meine abstrakte Klasse einige konkrete Methoden hat.

2voto

bryanbcook Punkte 15032

Eine der Hauptmotivationen für die Verwendung einer abstrakten Klasse ist die Ermöglichung von Polymorphismus innerhalb Ihrer Anwendung - d.h. Sie können zur Laufzeit eine andere Version ersetzen. Dies ist im Grunde genommen dasselbe wie die Verwendung einer Schnittstelle, mit dem Unterschied, dass die abstrakte Klasse ein gemeinsames "Plumbing" bietet, das oft als Schablonenmuster .

Aus Sicht des Unit-Tests sind zwei Dinge zu beachten:

  1. Interaktion Ihrer abstrakten Klasse mit den ihr verwandten Klassen . Die Verwendung eines Mock-Testing-Frameworks ist für dieses Szenario ideal, da es zeigt, dass Ihre abstrakte Klasse gut mit anderen zusammenarbeitet.

  2. Funktionalität der abgeleiteten Klassen . Wenn Sie benutzerdefinierte Logik für Ihre abgeleiteten Klassen geschrieben haben, sollten Sie diese Klassen isoliert testen.

edit: RhinoMocks ist ein großartiges Mock-Testing-Framework, das Mock-Objekte zur Laufzeit erzeugen kann, indem es dynamisch von Ihrer Klasse ableitet. Dieser Ansatz kann Ihnen unzählige Stunden der Handkodierung von abgeleiteten Klassen ersparen.

2voto

shreeram banne Punkte 526

Erstens, wenn abstrakte Klasse enthielt einige konkrete Methode Ich denke, Sie sollten dies tun als dieses Beispiel

 public abstract class A 

 {

    public boolean method 1
    {
        // concrete method which we have to test.

    }

 }

 class B extends class A

 {

      @override
      public boolean method 1
      {
        // override same method as above.

      }

 } 

  class Test_A 

  {

    private static B b;  // reference object of the class B

    @Before
    public void init()

      {

      b = new B ();    

      }

     @Test
     public void Test_method 1

       {

       b.method 1; // use some assertion statements.

       }

   }

1voto

Arpit Aggarwal Punkte 24466

Nach der Antwort von @patrick-desjardins habe ich die abstrakte und ihre Implementierungsklasse zusammen mit @Test wie folgt:

Abstrakte Klasse - ABC.java

import java.util.ArrayList;
import java.util.List;

public abstract class ABC {

    abstract String sayHello();

    public List<String> getList() {
        final List<String> defaultList = new ArrayList<>();
        defaultList.add("abstract class");
        return defaultList;
    }
}

Als Abstrakte Klassen können nicht instanziiert werden, aber sie können unterklassifiziert werden , konkrete Klasse DEF.java ist wie folgt:

public class DEF extends ABC {

    @Override
    public String sayHello() {
        return "Hello!";
    }
}

@Test Klasse, um sowohl abstrakte als auch nicht-abstrakte Methoden zu testen:

import org.junit.Before;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.contains;
import java.util.Collection;
import java.util.List;
import static org.hamcrest.Matchers.equalTo;

import org.junit.Test;

public class DEFTest {

    private DEF def;

    @Before
    public void setup() {
        def = new DEF();
    }

    @Test
    public void add(){
        String result = def.sayHello();
        assertThat(result, is(equalTo("Hello!")));
    }

    @Test
    public void getList(){
        List<String> result = def.getList();
        assertThat((Collection<String>) result, is(not(empty())));
        assertThat(result, contains("abstract class"));
    }
}

1voto

banduki Punkte 27

Wenn eine abstrakte Klasse für Ihre Implementierung geeignet ist, testen Sie (wie oben vorgeschlagen) eine abgeleitete konkrete Klasse. Ihre Annahmen sind richtig.

Um zukünftige Verwirrung zu vermeiden, sollten Sie wissen, dass diese konkrete Testklasse keine Attrappe ist, sondern eine gefälscht .

Streng genommen ist ein spiegeln. wird durch die folgenden Merkmale definiert:

  • Ein Mock wird anstelle jeder einzelnen Abhängigkeit der zu testenden Subjektklasse verwendet.
  • Ein Mock ist eine Pseudo-Implementierung einer Schnittstelle (Sie erinnern sich vielleicht, dass Abhängigkeiten in der Regel als Schnittstellen deklariert werden sollten; ein Hauptgrund dafür ist die Testbarkeit)
  • Die Verhaltensweisen der Schnittstellenmitglieder des Mocks - ob Methoden oder Eigenschaften -- werden zur Testzeit bereitgestellt (wiederum durch Verwendung eines Mocking-Frameworks). Auf diese Weise vermeiden Sie die Kopplung der zu testenden Implementierung mit der Implementierung ihrer Abhängigkeiten (die alle ihre eigenen diskreten Tests haben sollten).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X