2016-08-01 1 views
1

Imaginez que j'ai un service:Test d'une unité avec la classe implicite dans Scala

class ServiceA(serviceB: ServiceB) { 

    import Extractor._ 

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

} 

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

Je veux la méthode extract à une définition implicite car elle ne se rapporte pas directement à A type/domaine et est une solution extension ad hoc spécifique.

Maintenant, je voudrais écrire un test unitaire très simple qui confirme que serviceB.send est appelé.

Pour cela, je moque service et passe un A raillé à send. Ensuite, je pourrais simplement affirmer que serviceB.send a été appelé avec le A raillé.

Comme vu dans l'exemple, la méthode send effectue également une transformation sur le paramètre typeA, donc je devrais utiliser la méthode extract pour retourner la valeur spécifiée. Cependant, A n'a pas la méthode extract - il vient du implicit class. Donc la question est - comment puis-je me moquer de la classe implicite comme dans l'exemple ci-dessus que les importations ne sont pas des citoyens de première classe.

Répondre

0

Si vous souhaitez spécifier un tas de méthodes d'extraction personnalisées, vous pouvez faire quelque chose comme ceci:

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) 
    } 

} 

Vous avez donc essentiellement une famille de type fermé qui est pré-matérialisée par cas, les objets, qui sont sans doute seulement utile dans un match. Mais cela vous permettrait de tout découpler.

Si vous ne voulez pas mélanger cela avec Extractor, appelez-les autrement et suivez la même approche, vous pouvez ensuite tout mélanger avec un contexte lié.

Ensuite, vous pouvez l'utiliser avec:

println(Extractor(5)) 

Pour les tests, il suffit de remplacer les implicits disponibles si vous avez besoin. Un peu de travail, mais pas impossible, vous pouvez simplement contrôler la portée et vous pouvez espionner les appels de méthode que vous voulez.

Par exemple, au lieu de import Extractor._ avez un autre objet avec une logique de test uniquement où vous pouvez utiliser des mocks ou une implémentation alternative.