2017-05-15 2 views
0

Ich gehe durch den Kurs Functional Programming Principles in Scala auf Coursera. Es ist ein Beispiel für die Umsetzung des Peano numbers, die so geht:So testen Sie Peano Zahlen

abstract class Nat { 
    def isZero: Boolean 
    def predecessor: Nat 
    def successor: Nat = new Succ(this) 
    def +(that: Nat): Nat 
    def -(that: Nat): Nat 
} 

object Zero extends Nat { 
    def isZero = true 
    def predecessor: Nat = throw new Error("0.predecessor") 
    def +(that: Nat): Nat = that 
    def -(that: Nat): Nat = if (that.isZero) this else throw new Error("negative number") 
} 

class Succ(n: Nat) extends Nat { 
    def isZero: Boolean = false 
    def predecessor: Nat = n 
    def +(that: Nat): Nat = new Succ(n + that) 
    def -(that: Nat): Nat = if (that.isZero) this else n - that.predecessor 
} 

Ich schrieb einige Unit-Tests. Die meisten des Passes, aber die Folgendes - geschrieben in naiven Weise - aus offensichtlichen Gründen (Vergleich verschiedener Instanzen) versagt:

trait Fixture { 
    val one = new Succ(Zero) 
    val two = new Succ(one) 
} 

test("successor of zero is one") { 
    new Fixture { 
    assert(Zero.successor == one) 
    } 
} 

test("successor of one is two") { 
    new Fixture { 
    assert(one.successor == two) 
    } 
} 

test("one plus zero is one") { 
    new Fixture { 
    assert((one + Zero) === one) 
    } 
} 

test("one plus one is two") { 
    new Fixture { 
    assert((one + one) === two) 
    } 
} 

Meine Frage ist: wie ein Unit-Test durchgeführt werden soll, die erfolgreich testet + und - Operationen auf Peano-Nummern?

Nur für den Fall, hier finden Sie remaining unit tests.

+0

Wie würden Sie diesen Kurs tatsächlich verwenden? Kannst du keinen Gleichheitsoperator schreiben? Bei den aktuellen Operationen könnte man beispielsweise immer überprüfen, ob der Vorgänger von einem keinen Vorgänger hat und die Dinge auf diese Weise unbeholfen kettet. – JETM

+1

Warum ist Ihre Succ-Klasse keine Fallklasse? Es würde alles einfacher machen (außer du hast noch nichts davon gehört). –

+0

@JETM Es ist nur eine Demonstration, wie Werte Objekte sein können. Ich habe begonnen, Komponententest zu schreiben, nur um das Prinzip besser zu verstehen. Ja, das war meine erste Idee, zu zählen, wie viele Vorgänger zu "Zero" sind, aber ich wandere, wenn es etwas idiomatischer zu * Peano Zahlen * gibt. –

Antwort

1

Dank von Cyrille Corpet andeuten, es scheint mir, dass es elegant ist case class zu verwenden, die „durch die Struktur, die nicht mit Hilfe vergleicht“. Alle Komponententests laufen jetzt ohne Änderung ab.

case class Succ(n: Nat) extends Nat { 
    def isZero: Boolean = false 
    def predecessor: Nat = n 
    def +(that: Nat): Nat = new Succ(n + that) 
    def -(that: Nat): Nat = if (that.isZero) this else n - that.predecessor 
} 
-1

bei Ihren Tests Blick scheint es, dass Sie Gleichheitsbedingungen testen möchten, sollten Sie eine Funktion für das schreiben:

def eq(i: Nat, j: Nat): Boolean = 
    if (i.isZero | j.isZero) 
    i.isZero == j.isZero 
    else 
    eq(i.predecessor, j.predecessor) 

Der Ihre === & ==-eq durch Aufruf ersetzen. Sie könnten auch die gleiche Methode überschreiben, anstatt diese als externe (Test-) Funktion zu verwenden.