2014-11-20 140 views
3

我的第一個問題question已被回答,但它發現了我遇到的另一個問題。這是場景。使用Scalamock在scala中使用ClassTag的嘲諷方法

實施例的代碼(從前面的問題展開)

模型:

case class User (first: String, last: String, enabled: Boolean) 

組件定義:

trait DataProviderComponent { 
    def find[T: ClassTag](id: Int): Try[T] 
    def update[T](data: T): Try[T] 
} 

一個具體組件實現的(更新實施):

class DbProvider extends DataProviderComponent { 
    override def find[T: ClassTag](id: Int): Try[T] = { 
    Try { 
     val gson = new Gson() 
     val testJson = """{"first": "doe", "last": "jane", "enabled": false}""" 

     gson.fromJson(testJson, implicitly[ClassTag[T]].runtimeClass).asInstanceOf[T] 
    } 
    } 

    override def update[T](data: T): Try[T] = ??? 
} 

系統某處組件IMPL隱用法:

implicit val provider = new DbProvider() 

class UserRepsitory(implicit provider: DataProviderComponent) { 
    def userEnabled(id: Int): Boolean = { 
    val user = provider.find[User](id) 
    user.isSuccess && user.get.enabled 
    } 
} 

單位的Test1,試圖模擬出提供商,以便隔離存儲庫的測試。這不起作用,運行測試時會拋出以下錯誤。我期望這是因爲ClassTag的用法,因爲當我創建另一個不使用ClassTag的示例時,它工作正常。

org.scalamock.MockFunction2不能轉換到org.scalamock.MockFunction1 java.lang.ClassCastException:org.scalamock.MockFunction2不能轉換到org.scalamock.MockFunction1

class UserRepository$Test1 extends FunSuite with Matchers with MockFactory { 
    test("invalid data request should return false") { 
    implicit val mockProvider: DataProviderComponent = mock[DataProviderComponent] 
    (mockProvider.find[User] _).expects(13).returns(Failure[User](new Exception("Failed!"))) 

    val repo = new UserRepsitory() 
    repo.userEnabled(13) should be (false) 
    } 
} 

單位的Test2的工作,但難以維持,需要更多的代碼:

class UserRepository$Test2 extends FunSuite with Matchers with MockFactory { 
    test("invalid data request should return false") { 
    class FakeProvider extends DataProviderComponent { 
     override def find[T:ClassTag](id: Int): Try[T] = Failure[T](new Exception("Failed!")) 
     override def update[T](data: T): Try[T] = ??? 
    } 

    implicit val provider = new FakeProvider() 
    val repo = new UserRepsitory() 
    repo.userEnabled(13) should be (false) 
    } 
} 

單位Test3的正常工作,但 - 只是用於測試CLA ssTag實施:

class UserRepository$Test3 extends FunSuite with Matchers with MockFactory { 
    test("prove sut works") { 
    implicit val provider = new DbProvider() 
    val repo = new UserRepsitory() 
    val user = repo.userEnabled(13) 
    println(user.toString) 
    } 
} 

我使用ClassTag錯誤或是模擬不能正確地模擬它嗎?

回答

4

這是類似的:ScalaMock User Guide: Mocking methods with implicit params - 有一個隱含的ClassTag參數,所以你必須說服 Scala的編譯器,find[T](id:Int)(m: ClassTag[T])應該轉換爲MockFunction2

下面的代碼工作與ScalaMock 3.2:

package com.paulbutcher.test.mock 

import org.scalamock.scalatest.MockFactory 
import org.scalatest.{ FlatSpec, ShouldMatchers } 

import scala.reflect.ClassTag 
import scala.util.{ Failure, Try } 

case class User(first: String, last: String, enabled: Boolean) 

trait DataProviderComponent { 
    def find[T: ClassTag](id: Int): Try[T] 
    def update[T](data: T): Try[T] 
} 

class UserRepsitory(implicit provider: DataProviderComponent) { 
    def userEnabled(id: Int): Boolean = { 
    val user = provider.find[User](id) 
    user.isSuccess && user.get.enabled 
    } 
} 

class ClassTagTest extends FlatSpec with ShouldMatchers with MockFactory { 
    behavior of "ScalaMock" 

    it should "handle mocking methods with class tags" in { 
    implicit val mockProvider: DataProviderComponent = mock[DataProviderComponent] 
    (mockProvider.find[User](_: Int)(_: ClassTag[User])).expects(13, *).returns(Failure[User](new Exception("Failed!"))) 

    val repo = new UserRepsitory() 
    repo.userEnabled(13) should be(false) 
    } 
} 
+0

嗯微妙,謝謝修復它。不知道我是否喜歡它:) - 我覺得我需要更像編譯器而不是開發人員。 – IUnknown 2014-11-21 16:21:04