2013-01-11 21 views
5

完全披露:我對嘲笑和嘲諷框架非常陌生。我試圖使用ScalaMock,因爲它看起來像ScalaTest使用的'默認'模擬框架,但我很高興使用任何其他與ScalaTest兼容的框架。ScalaMock。模擬需要參數的類

問題:我在Scala中編寫了一個與套接字對話的類。這個類有一個類型參數,它與哪個套接字交談,其中一個參數是用於創建該類型套接字的工廠。它具有簽名:

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

我希望能夠通過提供一個模擬SocketClient編寫單元測試這一類,所以我的測試代碼沒有連接到一個真正的插座,但我不能工作了解如何使用ScalaMock做到這一點。

我的測試代碼如下所示:

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

顯然將不能編譯,因爲SocketClient預計到插座作爲參數的路徑,但我不能叫mock[SocketClient(s)],因爲這不是一個類型的,我可以因爲模擬不會將傳遞給它的類型的參數作爲自己的參數,所以不需要調用mock[SocketClient](s)

那麼我怎麼能寫一個模擬SocketClient工廠傳遞給我的掃描儀?我甚至無法解決如何模擬需要參數的類!

+0

我是ScalaMock的作者。你使用哪個版本的Scala和哪個版本的ScalaMock? ScalaMock2與ScalaMock3的答案不同。 –

+0

斯卡拉模擬3與斯卡拉2.10.0 – jangoolie

回答

3

洞察力是你需要模擬的是socketClientFactory。然後設置它返回一個模擬SocketClient

考慮:

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 
} 

(側面說明 - 不能用於confPath默認值,因爲沒有默認值socketClientFactory)。

那麼這應該讓你開始(這是斯卡拉2.9.x和ScalaMock2 - 2.10.x與ScalaMock3會略有不同,但沒有太多的話):

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

爲了完整起見,這裏的同測試在斯卡拉2.10.0和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

我不知道這是如何克服這一事實,SocketClient接受1個參數。我不能寫: val mockClient = mock [SocketClient] mockFactory.expects(「Some Socket Name」)。returns(mockClient) 因爲mock [SocketClient]不會編譯。您是否建議我修改SocketClient以使所有參數都沒有參數或具有默認值?即使沒有違約是有道理的。 非常感謝您回答順便說一句。 – jangoolie

+1

啊,對不起 - 我第一次錯過了那個皺紋。現在,ScalaMock3只能模擬特徵和無參數類。但是,如果你控制SocketClient,你應該還可以 - 創建一個定義方法並在你的類中實現它的trait:trait SocketClientBase;類SocketClient(...)擴展了SocketClientBase。那麼你可以模擬SocketClientBase,你應該很好?或者我錯過了什麼? –

+0

另外值得注意的即使我完全複製你的代碼,我無法得到它編譯。我得到: 重寫方法nestedSuites在類型=> scala.collection.immutable.IndexedSeq [org.scalatest.Suite]的trait SuiteMixin中; [error] method nestedSuites in trait Suite => List [org.scalatest.Suite]具有不兼容的類型 [error] class ScannerTest使用MockFactory擴展FunSuite { – jangoolie