2016-06-21 29 views
0

我有以下代码:有什么办法嘲笑Singleton对象在斯卡拉

trait Calculator { 

    def add(x:Int, y:Int):Int 
    def multiply(x:Int,y: Int):Int 
} 

trait MyCalculator extends Calculator { 

    override def add(x: Int, y: Int): Int = x+y //in real live it calls remote service which is not avaialble in test 

    override def multiply(x: Int, y: Int): Int = x*y //in real live it calls remote service which is not avaialble in test 
} 

object MyCalculator extends MyCalculator 

现在我有计算器服务:

trait CalculatorServiceTrait { 

    def calculate(x:Int,sign:String,y:Int):Int 
} 

trait CalculatorService extends CalculatorServiceTrait{ 
    override def calculate(x: Int, sign: String, y: Int): Int = { 
    sign match{ 
     case "+" => MyCalculator.add(x,y) 
     case "*" => MyCalculator.multiply(x,y) 
     case _ => 0 
    } 
    } 
} 

object CalculatorService extends CalculatorService 

现在我想使用的Mockito带来嘲笑MyCalculator我不正确的结果。

"Calculator Service" should{ 

    "return 0 when 2 and 2 used " in{ 

     val MyCalculatorMock = mock[MyCalculator] 
     when(MyCalculatorMock.multiply(2,2)).thenReturn(0) 
     class CalculatorServiceUnderTest extends CalculatorService with MyCalculator 

     new CalculatorServiceUnderTest with MyCalculator 
     val c = new CalculatorServiceUnderTest 
     val result = c.calculate(2,"+",2) 
     result shouldEqual(0) 
    } 
    } 

,但我仍然得到“4”,而不是“0”

有什么办法来处理这样的测试案例?

PS:我可以改变某个类或特性的实现,但这样做的全球重构可能会出现问题

+0

我认为这是因为你在嘲笑'乘法',然后在你的测试中使用'+'符号。 –

回答

3

那么,你的模仿对象是不是在任何地方使用,因此,它不是一个很大的惊喜,它永远不会变叫,是吗?

要回答你的问题,不,你不能嘲笑一个单身人士,这就是为什么直接使用它不是一个好主意。外部依赖于组件需要从外部提供,以便组件可以独立测试。做你想做什么

一种方法是使CalculatorService类和MyCalculator实例传递给构造函数的参数:

class CalculatorService(calc: MyCalculator = MyCalculator) 
    extends CalculatorServiceTrait { 
    override def calculate(x: Int, sign: String, y: Int): Int = sign match { 
     case "+" => calc.add(x,y) 
     case "*" => calc.multiply(x,y) 
     case _ => 0 
    } 
    } 
} 

那么,在您的测试,你可以这样做: val testMe = new CalculatorService(mock[MyCalculator])

如果必须保持某种原因特质,你可以使用“蛋糕模式”提供外部依赖:

trait CalculatorProvider { 
    def calc: MyCalculator 
} 

trait CalculatorService { self: CalculatorProvider => 
... 
} 

object CalculatorService extends CalculatorService with CalculatorProvider { 
    def calc = MyCalculator 
} 


val testMe = new CalculatorService with CalculatorProvider { 
    val calc = mock[MyCalculator] 
}