4 Stimmen

Unit-Tests für untergeordnete Klassen

Nehmen wir an, wir haben diese sehr einfache Klassenhierarchie:

public class SomeMath
{
    public int Add(int x, int y)
    {
        return x + y;
    }
}

public class MoreMath : SomeMath
{
    public int Subtract(int x, int y)
    {
        return x - y;
    }
}

Sollte ich Tests für die Add Methode, wenn ich Tests für die MoreMath Klasse? Oder sollte ich mich nur um diese Methode kümmern, wenn ich die SomeMath Klasse? Allgemeiner ausgedrückt: Sollte ich alle Methoden einer Klasse testen, oder sollte ich nur "neue" Methoden testen?

Ich kann für beide Seiten einige Gründe anführen. Wenn man zum Beispiel alle Methoden testet, wird man am Ende dasselbe mehr als einmal testen, was nicht so gut ist und langweilig werden kann. Aber wenn man nicht alle Methoden testet, kann eine Änderung in SomeMath könnte die Verwendungen von MoreMath ? Was irgendwie auch schlecht wäre. Ich nehme an, es hängt wahrscheinlich auch ein bisschen vom Fall ab. Zum Beispiel, ob es eine Klasse erweitert, über die ich Kontrolle habe oder nicht. Aber wie auch immer, ich bin ein totaler Test-Neuling, also bin ich neugierig zu erfahren, was Leute, die schlauer sind als ich, darüber denken :-)

2 Stimmen

In Anbetracht der Tatsache, dass Sie eine Art von Frage gestellt haben, auf die es keine eindeutige richtige oder falsche Antwort gibt, halte ich es für eine schlechte Idee, eine Antwort nach nur 7 Minuten zu akzeptieren.

7voto

tvanfosson Punkte 506878

Normalerweise würde ich das Verhalten in der untergeordneten Klasse nicht testen, es sei denn, die untergeordnete Klasse ändert das Verhalten gegenüber dem in der übergeordneten Klasse erwarteten Verhalten. Wenn sie das gleiche Verhalten verwendet, besteht keine Notwendigkeit, sie zu testen. Wenn Sie vorhaben, die übergeordnete Klasse grundlegend zu ändern, die untergeordnete Klasse aber noch das alte Verhalten benötigt, würde ich zunächst Tests in der untergeordneten Klasse erstellen, um das erforderliche Verhalten zu definieren, und dann die Änderungen in den übergeordneten Tests und den nachfolgenden Codeänderungen vornehmen. Dies folgt dem YAGNI-Prinzip - Sie werden es nicht brauchen - und verzögert die Implementierung der untergeordneten Tests, bis sie tatsächlich einen Zweck haben.

0 Stimmen

Ich denke, diese Antwort geht davon aus, dass Unit-Tests nur nach TDD-Methode geschrieben werden. Meiner Meinung nach ist das nur die Hälfte der Antwort, aber siehe meine Antwort für eine ausführlichere Untersuchung.

1voto

Razzie Punkte 30442

Ich würde nur die Add Methode der Klasse SomeMath. Wenn MoreMath nur erbt und absolut nichts Neues tut, dann würde das Schreiben von Tests für beide reinen doppelten Code darstellen, nichts weiter. Es ist immer gut, ein wenig pragmatisch mit diesen Dingen imho zu sein.

0voto

Mark Seemann Punkte 216836

Zunächst einmal denke ich, dass es mindestens zwei Faktoren gibt, die Ihre Entscheidung für das eine oder das andere beeinflussen können:

  • Was ist der Zweck des Erbes?
  • Welchen Zweck hat der betreffende Test?

In TDD-Szenarien würde ich dazu neigen, einen einzigen Testfall für MoreMath zu schreiben, der verifiziert, dass er von SomeMath abgeleitet ist, und dann alle von SomeMath geerbten Mitglieder als abgedeckt betrachten.

Das bedeutet jedoch, dass es aus gestalterischer Sicht ein wichtiger Gestaltungsaspekt ist, dass MoreMath von SomeMath abgeleitet ist. Dies wäre definitiv der Fall, wenn Sie SomeMath in einer polymorphen Weise verwenden. Es wäre jedoch nicht der Fall, wenn Sie einfach Vererbung zur Wiederverwendung verwenden (was allerdings nicht empfohlen wird).

Im letzteren Fall (Vererbung dient der Wiederverwendung) besteht keine konzeptionelle Verbindung zwischen der übergeordneten und der untergeordneten Klasse, und Sie könnten versucht sein, die Vererbung in Zukunft aufzuheben. In solchen Fällen ist ein Test, der überprüft, ob die übergeordnete Klasse korrekt ist, ein schlechter Schutz.

Unter dem Gesichtspunkt der Qualitätssicherung (QA) sollte jedes einzelne Mitglied jeder Klasse rigoros getestet werden. Das bedeutet, dass Sie den Testcode für jede untergeordnete Klasse wiederholen sollten, selbst wenn der Testcode derselbe wäre, da Sie überprüfen müssen, dass keine virtuelle Methode auf unerwartete Weise überschrieben wurde. Um jedoch DRY zu bleiben, können Sie sie als parametrisierte Tests schreiben oder ein Tool wie Pex .

Ich persönlich komme selten bis zur QA-Phase. Normalerweise ist die während der TDD erstellte Testsuite ein ausreichendes Sicherheitsnetz... aber das hängt alles von der Art der Software ab, die Sie erstellen.

0 Stimmen

Ich habe dies zur Antwort gemacht, da es mehr Winkel abdeckt :)

0voto

Ian Johnson Punkte 2086

Bei meiner derzeitigen Arbeitsstelle sind wir auf ein ähnliches Problem gestoßen, bei dem wir Schnittstellen entwickeln, aber sicherstellen wollten, dass sich jede Implementierung der Schnittstelle korrekt verhält (z. B. sollten sich verschiedene Datenschichten unabhängig von der Implementierung dieser Schicht gleich verhalten). Die Lösung (mit NUnit) bestand darin, eine Vererbungsstruktur innerhalb der Unit-Tests zu verwenden:

public interface ICalculator
{
  public int Add(int a, int b)
}

public class Calculator : ICalculator
{
  public int Add(int a, int b) { return a + b; }
}

public class TestCalculatorInterface
{
   public abstract SomeMath GetObjectToTest();

   [Test]
   public void TestAdd()
   {
       var someMath = GetObjectToTest();
       ...
   }
}    

[TestFixture]
public class TestCalculator: TestCalculatorInterface
{
   public virtual Calculator GetObjectToTest() { return new Calculator(); }
}

Wir hätten nicht die [TestFixture] Attribut auf der Basisschnittstelle test, sondern haben das [Test] Attribut für alle Testmethoden. Die Website TestCalculator Klasse ist die [TestFixture] erbt aber alle Tests von der Basisklasse, so dass die Unterklasse nur für die Bereitstellung des Testobjekts für diese Schnittstelle verantwortlich ist.

Ich würde in Ihrem Fall ein ähnliches Muster anwenden, so dass die Tests für alle Klassen ausgeführt werden, aber nur einmal geschrieben werden.

-1voto

Matt Howells Punkte 38730

Ich würde meine Testklasse für MoreMath erben von der Testklasse für SomeMath und erbt somit alle Tests dieser Klasse. Das bedeutet, dass ich nur zusätzliche Tests für die neuen Funktionen schreiben muss, aber alle Funktionen der Unterklasse werden vollständig getestet.

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