2017-04-24 2 views
0

Ich habe eine Funktion in Scala alsWie eine Funktion mit Blick Grenzen als Argument verspotten

object MyService extends MyTrait {  
    def myMethod[T <% InvokableBuilder[MyClass]](builder: T): MyResponse = { 
    //do something 
    } 
} 

folgt Ich versuche, diese Funktion zu verspotten mit Mockito wie folgt

val mockService = mock[MyTrait] 

doReturn(info).when(mockService).myMethod(any()) 

I die folgenden Fehler obwohl ich nur ein Argument in der Funktion

org.mockito.exceptions.misusing.InvalidUseOfMatchersException habe: Ungültige Verwendung von argume nt Matcher! [info] 2 Matcher erwartet, 1 aufgezeichnet:

Antwort

1

Ihr Problem ist: scala ist nicht java.

Ihre implizite Annahme ist: "diese kleine Scala-Methode wird dort in etwas Ähnliches in Java übersetzt, und damit kann ich einfach Mockito verwenden, um damit umzugehen".

Falsch. Sie erstellen hier eine Scala Objekt Definition; und wenn ich mich richtig erinnere; Objekt in Scala ... übersetzt in statische in Java (siehe zum Beispiel here).

So müssen Sie sich auf den ersten Blick wahrscheinlich zu PowerMock (ito) resp. JMockit, um diese statischen Elemente zu verspotten. (und meine übliche Warnung: Verwenden Sie nicht PowerMock; weil spotten statische Sachen ist eine schlechte Idee). Und wie Philipp M in seinem Kommentar darauf hinweist: Spott statisch ist wirklich schlechte Praxis angesehen. Sie sollten lieber versuchen, die "Trait" -Seite der Dinge hier zu verspotten.

Also die wirkliche Antwort ist: Sie müssen wissen, was Sie tun. Mockito ist für java geschrieben. Sie können nicht einfach davon ausgehen, dass alles, was Sie in scala schreiben und das irgendwie wie Java aussieht, leicht den Konzepten zugeordnet werden kann, an denen Mockito arbeitet.

Um wirklich zu verstehen, was vor sich geht; Sie sollten sich zuerst die Klassendateien ansehen, die der scala-Compiler in Ihrem Fall erstellt; prüfe die Methodensignatur; und denke selbst: "Wenn ich diese Methode im Java-Quellcode aufrufen müsste, wie würde ich das machen?" und arbeite von dort.

+0

ich mit der ersten Hälfte dieser Antwort einverstanden - Scala 'object's Singletons und sollten als solche behandelt werden. Was mir nicht gefällt, ist die Idee, PowerMock zu benutzen, um das zu umgehen und Bytecode während der Testausführung zu manipulieren. Meiner Meinung nach wäre es viel besser, wenn das 'Objekt' ein' Merkmal' implementiert, wie Sie es bereits getan haben, und stattdessen das Merkmal verspotten. –

+0

Entschuldigung, meine Antwort wurde zur Hälfte geschrieben, und geben Sie es ein :) –

+0

Got it ... und fügte das der Antwort hinzu. Und ich stimme völlig zu. – GhostCat

0

Ich habe deinen // etwas geändert ??? so wäre es zu kompilieren, gedruckt dann den Code am Ende des Parsers Phase:

$scalac MyService.scala -Xprint:parser 
[[syntax trees at end of     parser]] // MyService.scala 
package <empty> { 
    object MyService extends MyTrait { 
    def <init>() = { 
     super.<init>(); 
    () 
    }; 
    def myMethod[T](builder: T)(implicit evidence$1:_root_.scala.Function1[T,InvokableBuilder[MyClass]]): MyResponse = $qmark$qmark$qmark 
    } 
} 

Wie Sie sehen können, die myMethod einen zweiten Parameterliste aufgrund Ihrer Ansicht gebunden. Ich bin nicht sicher, wie Sie das mit Mockito verhöhnen würden, aber ich schlage vor, ScalaMock auszuprobieren.

Hinweis: Ansichtsgrenzen sind veraltet - ich würde vorschlagen, sie durch einen impliziten Parameter zu ersetzen (sehen Sie, wie der scalac Parser das oben tut).

Längliche Beispiel:

import org.scalamock.scalatest.MockFactory 
import org.scalatest.FlatSpec 

import scala.language.implicitConversions 

class FooTest extends FlatSpec with MockFactory { 

    trait MyTrait { 
    def myMethod[T](builder: T)(implicit ev$1: T => InvokableBuilder[MyClass]): MyResponse 
    } 

    trait InvokableBuilder[T] 

    class MyClass 

    class MyResponse 

    class Foo 

    object MyService extends MyTrait { 
    def myMethod[T](builder: T)(implicit ev$1: T => InvokableBuilder[MyClass]): MyResponse = { 
     //do something 
     ??? 
    } 
    } 

    behavior of "Foo" 

    it should "foo" in { 
    val x = mock[MyTrait] 

    implicit val fooConvert: Foo => InvokableBuilder[MyClass] = ??? 
    (x.myMethod(_: Foo)).expects(*).once() 
    } 

} 
Verwandte Themen