2013-01-11 12 views
5

Pełne ujawnienie: Jestem bardzo nowy w szyderczym i szyderczym środowisku. Próbuję użyć ScalaMock, ponieważ wydawało się, że jest to "domyślna" szydercza struktura do użycia z ScalaTest, ale cieszę się, że mogę użyć dowolnego innego frameworka kompatybilnego z ScalaTest.ScalaMock. Kpić z klasy, która przyjmuje argumenty:

Problem: napisałem w Scali klasę, która rozmawia z gniazdem. Klasa ma typ parametru, z jakim gniazdem ma rozmawiać, a jeden z jego argumentów jest fabryką do tworzenia gniazd tego typu. Ma podpisem:

class XScanner[T <: SocketClient](
    confPath: String = "/etc/default/configPath", 
    socketClientFactory: String => T 
) extends ScannerBase(path) 

Chciałbym, aby móc pisać testy jednostkowe w tej klasie poprzez dostarczanie mock SocketClient więc mój kod testu nie trzeba podłączać do gniazda rzeczywistego, ale nie mogę pracować jak to zrobić z ScalaMock.

Mój kod testowy wygląda następująco:

val t = new XScanner[SocketClient](confPath, (s: String) => mock[SocketClient]) 

wyraźnie, że nie będzie skompilować ponieważ SocketClient spodziewa ścieżkę do gniazda jako argument, ale nie mogę zadzwonić mock[SocketClient(s)] bo to nie jest rodzaj i mogę 't wywołaj mock[SocketClient](s), ponieważ makieta nie przyjmuje argumentów typu przekazanego do niego jako własnych argumentów.

Jak mogę napisać próbną fabrykę SocketClient, aby przejść do mojego skanera? Nie potrafię nawet wyobrazić sobie, jak kpić z klasy, która przyjmuje argumenty!

+0

Jestem autorem ScalaMock. Z której wersji Scala i której wersji ScalaMock korzystasz? Odpowiedzi są różne dla ScalaMock2 versus ScalaMock3. –

+0

Scala Mock 3 ze Scala 2.10.0 – jangoolie

Odpowiedz

3

Wgląd w to, że trzeba udawać, że jest socketClientFactory. A następnie ustawić go, aby zwrócić próbę SocketClient.

Dane:

trait SocketClient { 
    def frobnicate(): Unit 
} 

class ScannerBase(path: String) 

class XScanner[T <: SocketClient](
    confPath: String = "/etc/default/configPath", 
    socketClientFactory: String => T 
) extends ScannerBase(confPath) { 
    val socket = socketClientFactory("Some Socket Name") 
    socket.frobnicate 
} 

(dygresja - swoją wartość domyślną confPath nigdy nie może być stosowane, ponieważ nie ma wartości domyślnej dla socketClientFactory).

to powinno Ci zacząć (to z Scala 2.9.x oraz ScalaMock2 - 2.10.x z ScalaMock3 będzie nieco inna, ale nie tak dużo):

import org.scalatest.FunSuite 
import org.scalamock.scalatest.MockFactory 
import org.scalamock.generated.GeneratedMockFactory 

class ScannerTest extends FunSuite with MockFactory with GeneratedMockFactory { 

    test("scanner") { 
    val mockFactory = mockFunction[String, SocketClient] 
    val mockClient = mock[SocketClient] 
    mockFactory.expects("Some Socket Name").returning(mockClient) 
    mockClient.expects.frobnicate 
    val scanner = new XScanner("path/to/config", mockFactory) 
    } 
} 

Dla kompletności, tutaj jest to samo test w Scala 2.10.0 i ScalaMock3:

import org.scalatest.FunSuite 
import org.scalamock.scalatest.MockFactory 

class ScannerTest extends FunSuite with MockFactory { 

    test("scanner") { 
    val mockFactory = mockFunction[String, SocketClient] 
    val mockClient = mock[SocketClient] 
    mockFactory.expects("Some Socket Name").returning(mockClient) 
    (mockClient.frobnicate _).expects() 
    val scanner = new XScanner("path/to/config", mockFactory) 
    } 
} 
+0

Nie jestem pewien, jak to przezwycięża fakt, że SocketClient ma 1 argument. Nie mogę napisać: val mockClient = pozoruj [SocketClient] mockFactory.expects ("Some Socket Name"). Return (mockClient) Ponieważ próbka [SocketClient] nie będzie się kompilować. Sugerujesz, że zmodyfikuję SocketClient tak, aby nie przyjmował żadnych argumentów lub miał domyślne wartości dla wszystkich argumentów? Nawet jeśli domyślne ustawienia nie mają sensu. Dziękuję bardzo za odpowiedź. – jangoolie

+1

Ach, przepraszam - za pierwszym razem tęskniłem za tą zmarszczką. Obecnie ScalaMock3 może tylko kpić z klas i klas bez argów. Ale jeśli kontrolujesz SocketClient, powinieneś być w porządku - stwórz cechę, która definiuje metody i implementuj je w klasie: cecha SocketClientBase; klasa SocketClient (...) rozszerza SocketClientBase. Wtedy możesz wyśmiać SocketClientBase i powinieneś być dobry? Czy może czegoś brakuje? –

+0

Również z notatki Nawet jeśli dokładnie skopiuję twój kod, nie mogę go skompilować.Otrzymuję: przesłonięcie metody nestedSuites in the Trait SuiteMixin typu => scala.collection.immutable.IndexedSeq [org.scalatest.Suite]; [błąd] metoda zagnieżdżona w obiekcie Cecha typu = = lista [org.scalatest.Suite] ma niekompatybilny typ klasa błędu [error] ScannerTest rozszerza FunSuite z MockFactory { – jangoolie

Powiązane problemy