2016-08-01 5 views
1

Stellen Ich habe einen Dienst:eine Einheit mit impliziter Klasse in Scala Testen

class ServiceA(serviceB: ServiceB) { 

    import Extractor._ 

    def send(typeA: A) = serviceB.send(typeA.extract) 

} 

object Extractor { 
    implicit class Extractor(type: A) { 
     def extract = ??? 
    } 
} 

Ich mag die extract Methode ein implizit definiert werden, da sie bezieht sich nicht direkt auf A Typen/Domain und eine Lösung spezifische Ad-hoc-Erweiterung.

Jetzt möchte ich einen sehr einfachen Komponententest schreiben, der bestätigt, dass serviceB.send aufgerufen wird.

Dafür spotte ich service und übergebe ein A an send gespottet. Dann könnte ich einfach behaupten, dass serviceB.send mit dem Mocked A aufgerufen wurde.

Wie im Beispiel zu sehen, die send Methode auch einige Transformation auf typeA Parameter, so würde ich müssen extract Methode, um meinen angegebenen Wert zurückgeben. A hat jedoch keine extract Methode - es kommt von der implicit class.

Die Frage ist also - wie verspotte ich die implizite Klasse wie im obigen Beispiel, da Importe keine Bürger erster Klasse sind.

Antwort

0

Wenn Sie eine Reihe von maßgeschneiderten Extrakt Methoden angeben möchten, können Sie etwas tun:

sealed trait Extractor[T] { 
    // or whatever signature you want 
    def extract(obj: T): String 
} 
object Extractor { 

    implicit case object IntExtractor extends Extractor[Int] { 
    def extract(obj: Int): String = s"I am an int and my value is $obj" 
    } 
    implicit case object StringExtractor extends Extractor[String] { 
    def extract(obj: String): String = s"I am " 
    } 

    def apply[A : Extractor](obj: A): String = { 
    implicitly[Extractor[A]].extract(obj) 
    } 

} 

So haben Sie im Grunde eine abgedichtete Familie, die Pre-materialisiert durch Fall Objekte, die sind wohl nur nützlich in einem match. Aber das würde dich alles entkoppeln lassen.

Wenn Sie dies nicht mit Extractor mischen möchten, nennen Sie sie etwas anderes und folgen Sie demselben Ansatz, Sie können dann alles mit einem Kontext gebunden mischen.

Dann können Sie diese mit verwenden:

println(Extractor(5)) 

Zum Testen einfach die verfügbaren implicits außer Kraft setzen, wenn Sie benötigen. Ein bisschen Arbeit, aber nicht unmöglich, Sie können einfach den Umfang kontrollieren und Sie können auf welche Methode auch immer Sie rufen wollen.

z. B. anstelle von import Extractor._ haben Sie ein anderes Objekt mit Test nur Logik, wo Sie Mocks oder eine alternative Implementierung verwenden können.

Verwandte Themen