2008-08-02 14 views
18

Ich möchte eine Funktion mit einem Tupel aus einer Reihe von Rand Fällen und normalen Werten testen. Zum Beispiel würde ich beim Testen einer Funktion, die true zurückgibt, wenn drei Längen gegeben werden, die ein gültiges Dreieck bilden, spezifische Fälle haben, negative/kleine/große Zahlen, Werte, die kurz übergelaufen sind, usw .; Hauptziel ist es, Kombinationen dieser Werte, mit oder ohne Wiederholung zu generieren, um eine Reihe von Testdaten zu erhalten.So verwenden Sie Kombinationen von Mengen als Testdaten

(inf,0,-1), (5,10,1000), (10,5,5), (0,-1,5), (1000,inf,inf), 
... 

Als Anmerkung: Ich weiß eigentlich die Antwort auf diese, aber es könnte hier für andere, und eine Herausforderung für Menschen hilfreich sein! --wird meine Antwort später veröffentlichen.

+0

[Abacus github] (https://github.com/foo123/Abacus) eine Kombinatorbibliothek für Node.JS, Python, PHP, Actionscript (ps ich bin der Autor) –

Antwort

14

Absolut, vor allem mit vielen diesen Permutationen/Kombinationen zu tun ich auf jeden Fall sehen, dass der erste Durchgang ein Problem sein würde.

Interessante Implementierung in Python, obwohl ich einen schönen in C und Ocaml basierend auf "Algorithmus 515" geschrieben habe (siehe unten). Er schrieb sein in Fortran, wie es damals für alle "Algorithmus XX" Papiere üblich war, gut, diese Versammlung oder c. Ich musste es neu schreiben und einige kleine Verbesserungen vornehmen, um mit Arrays, nicht mit Zahlenbereichen, zu arbeiten. Dieser arbeitet wahllos, ich arbeite immer noch daran, ein paar nette Implementierungen der in Knuth 4th volume fascicle 2 erwähnten zu bekommen. Ich werde eine Erklärung geben, wie das für den Leser funktioniert. Wenn jemand neugierig ist, würde ich nichts dagegen haben, etwas zu schreiben.

/** [combination c n p x] 
* get the [x]th lexicographically ordered set of [p] elements in [n] 
* output is in [c], and should be sizeof(int)*[p] */ 
void combination(int* c,int n,int p, int x){ 
    int i,r,k = 0; 
    for(i=0;i<p-1;i++){ 
     c[i] = (i != 0) ? c[i-1] : 0; 
     do { 
      c[i]++; 
      r = choose(n-c[i],p-(i+1)); 
      k = k + r; 
     } while(k < x); 
     k = k - r; 
    } 
    c[p-1] = c[p-2] + x - k; 
} 

~ "Algorithmus 515: Erzeugung eines Vektors aus dem lexikographischen Index"; Buckles, B. P., und Lybanon, M. ACM Transaktionen auf mathematische Software, Vol. 3, Nr. 2, Juni 1977.

+0

Was macht 'choose()' ? Liefert das grundsätzlich 'n-c [i]' '' p- (i + 1) 1'? – mkb

+0

@mkb Natürlich. – nlucaroni

+0

Es tut mir leid, ich folge dem Choose-Verhalten nicht. Es klingt, als ob es als selbstreflexiv definiert ist - wählen wählt. Können Sie mir sagen, was es einfacher macht? – CuppM

4

Interessante Frage!

Ich würde dies tun, indem Sie Kombinationen, etwa wie folgt in Python. Der schwierigste Teil ist wahrscheinlich die Überprüfung des ersten Durchgangs, d. H. if f(1,2,3) returns true, ist das ein korrektes Ergebnis? Sobald Sie dies verifiziert haben, ist dies eine gute Grundlage für Regressionstests.

Wahrscheinlich ist es eine gute Idee, eine Reihe von Testfällen zu erstellen, von denen Sie wissen, dass sie alle wahr sind (zB 3,4,5 für diesen Dreiecksfall), und eine Reihe von Testfällen, die Ihnen bekannt sind, sind alle falsch (zB 0,1, inf). Dann können Sie leichter überprüfen, ob die Tests korrekt sind.

 
# xpermutations from http://code.activestate.com/recipes/190465 
from xpermutations import * 

lengths=[-1,0,1,5,10,0,1000,'inf'] 
for c in xselections(lengths,3):  # or xuniqueselections 
    print c 
 
(-1,-1,-1); 
(-1,-1,0); 
(-1,-1,1); 
(-1,-1,5); 
(-1,-1,10); 
(-1,-1,0); 
(-1,-1,1000); 
(-1,-1,inf); 
(-1,0,-1); 
(-1,0,0); 
... 
2

Ich denke, dass Sie dies mit der Row Test Attribute (verfügbar in MbUnit und späteren Versionen von NUnit) tun können, wo Sie mehrere Sätze angeben konnten, um einen Komponententest zu füllen.

0

Während es möglich ist, viele Testdaten zu erstellen und zu sehen, was passiert, ist es effizienter zu versuchen, die verwendeten Daten zu minimieren.

Aus einer typischen QA-Perspektive möchten Sie verschiedene Klassifizierungen von Eingängen identifizieren. Erstellen Sie eine Reihe von Eingabewerten für jede Klassifizierung und bestimmen Sie die entsprechenden Ausgaben.

Hier ist ein Beispiel von Klassen von Eingang

  • gültige Dreiecken mit kleinen Zahlen Werte wie beispielsweise (1 Milliarde, 2, Milliarden, 2 Milliarden)
  • gültige Dreiecken mit großen Stückzahlen, wie beispielsweise (0,000001, 0,00002 , 0,00003)
  • gültig stumpfe Dreiecken, die ‚almost'flat wie (10, 10, 19,9999)
  • gültige acute Dreiecke, die 'nahezu' flach wie (10, 10, 0000001)
  • ungültige Dreiecken wi th mindestens ein negativer Wert
  • ungültige Dreiecken, wobei die Summe aus zwei die dritten
  • ungültigen Dreiecken gleich Seiten, wo die Summe von zwei Seiten größer ist als die dritten
  • Eingangswerte, die nicht numerisch sind

...

Sobald Sie mit der Liste der Eingabeklassifizierungen für diese Funktion zufrieden sind, können Sie die tatsächlichen Testdaten erstellen. Wahrscheinlich wäre es hilfreich, alle Permutationen jedes Elements zu testen. (zB (2,3,4), (2,4,3), (3,2,4), (3,4,2), (4,2,3), (4,3,2)) In der Regel finden Sie einige Klassifikationen, die Sie übersehen haben (z. B. das Konzept von inf als Eingabeparameter).

Zufällige Daten für einige Zeit kann auch hilfreich sein, die seltsame Fehler im Code finden können, aber im Allgemeinen nicht produktiv ist.

Wahrscheinlicher ist, dass diese Funktion in einem bestimmten Kontext verwendet wird, in dem zusätzliche Regeln angewendet werden (z. B. nur ganzzahlige Werte oder Werte müssen in Schritten von 0,01 sein.) Diese ergänzen die Liste der Klassifizierungen der Eingabeparameter.

4

Mit dem brandneuen Python 2.6, haben Sie eine Standardlösung mit dem itertools Modul, das das cartesianischen Produkt von Iterables zurück:

import itertools 

print list(itertools.product([1,2,3], [4,5,6])) 
    [(1, 4), (1, 5), (1, 6), 
    (2, 4), (2, 5), (2, 6), 
    (3, 4), (3, 5), (3, 6)] 

Sie können ein liefern „repeat“ Argument das Produkt mit einem iterable auszuführen und selbst:

print list(itertools.product([1,2], repeat=3)) 
[(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2), 
(2, 1, 1), (2, 1, 2), (2, 2, 1), (2, 2, 2)] 

Sie auch auch etwas mit Kombinationen zwicken:

print list(itertools.combinations('123', 2)) 
[('1', '2'), ('1', '3'), ('2', '3')] 

Und wenn um Fragen gibt es Permutationen:

print list(itertools.permutations([1,2,3,4], 2)) 
[(1, 2), (1, 3), (1, 4), 
    (2, 1), (2, 3), (2, 4), 
    (3, 1), (3, 2), (3, 4), 
    (4, 1), (4, 2), (4, 3)] 

Natürlich alles, was Hamlish nicht genau das gleiche tun, aber man kann sie in einer Weise verwenden oder eine andere Sie Problem zu lösen.

Denken Sie daran, dass Sie mit list(), tuple() und set() ein Tupel oder eine Liste in eine Menge und umgekehrt konvertieren können.