Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/.htaccess/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用于计算VAL的依赖于Scala测试的方法只执行一次_Scala_Mockito_Scalatest_Scalamock - Fatal编程技术网

用于计算VAL的依赖于Scala测试的方法只执行一次

用于计算VAL的依赖于Scala测试的方法只执行一次,scala,mockito,scalatest,scalamock,Scala,Mockito,Scalatest,Scalamock,我是scala新手,我正在尝试找出测试以下过程的最佳方法 我有一个类,它从构造函数参数中获取一个数字列表。该类支持列表上的各种操作,有些操作可能依赖于其他操作的输出。但每个选项只应按需执行计算,最多应执行一次。不应在构造函数中进行任何计算 示例类定义。 输入列表:列表[Int] x:返回一个向量,其中包含InputList中所有元素的平方 y:返回x中所有元素的总和 z:返回y的平方根 至于类实现,我想我能够想出一个合适的解决方案,但现在我不知道如何测试依赖操作树的计算只执行一次 课程实施方法1

我是scala新手,我正在尝试找出测试以下过程的最佳方法

我有一个类,它从构造函数参数中获取一个数字列表。该类支持列表上的各种操作,有些操作可能依赖于其他操作的输出。但每个选项只应按需执行计算,最多应执行一次。不应在构造函数中进行任何计算

示例类定义。 输入列表:列表[Int]

x:返回一个向量,其中包含InputList中所有元素的平方

y:返回x中所有元素的总和

z:返回y的平方根

至于类实现,我想我能够想出一个合适的解决方案,但现在我不知道如何测试依赖操作树的计算只执行一次

课程实施方法1:

这是我的第一个方法,我相信它可以完成这项工作,但是我不知道如何正确地测试它,所以我决定添加一些helper方法来确认它们只被称为helper方法

课程实施方法2:

我现在可以确认每个方法的每个依赖方法在必要时只调用一次

现在我如何为这些进程编写测试。我看到了一些关于mockito的帖子,并查看了文档,但没有找到我想要的内容。我看了以下几点:

演示如何测试函数是否被调用一次,然后如何测试其他函数是否依赖于调用的位置?

似乎很有希望,但我无法理解语法:

我想执行的示例测试


正如您所提到的,Mockito是一种方式,下面是一个示例:

class NumberOPSTest extends FunSuite with Matchers with Mockito {

  test("testSum") {
    val listoperations = smartMock[NumberOPS]
    when(listoperations.sum(any)).thenCallRealMethod()

    listoperations.sum(List(2, 4, 4)) shouldEqual 10

    verify(listoperations, never()).sqrt(any)
  }

}

好的,让我们把“预成熟优化”的争论留到下次讨论

mock用于存根/验证与代码的依赖关系(也称为其他类)的交互,而不是检查代码的内部,所以为了实现您想要的,您需要这样的东西

class Ops {
 def square(numbers: List[Int]): List[Int] = numbers.map(n => n*n)
 def sum(numbers: List[Int]): Int = numbers.sum
 def sqrt(num: Int): Double = scala.math.sqrt(num)
}

class Operations(nums: List[Int])(implicit ops: Ops) {
 lazy val x: List[Int] = ops.square(nums)
 lazy val y: Int = ops.sum(x)
 lazy val z: Double = ops.sqrt(y)
}

import org.mockito.{ ArgumentMatchersSugar, IdiomaticMockito}

class IdiomaticMockitoTest extends AnyWordSpec with IdiomaticMockito with ArgumentMatchersSugar
  "operations" should {
    "be memoised" in {
      implicit val opsMock = spy(new Ops)
      val testObj = new Operations(List(2, 4, 4))

      testObj.x shouldBe List(4, 16, 16)
      testObj.y shouldBe 36
      testObj.y shouldBe 36 //call it again just for the sake of the argument
      testObj.z shouldBe 6 //sqrt(36)
      testObj.z shouldBe 6 //sqrt(36), call it again just for the sake of the argument

      opsMock.sum(*) wasCalled once
      opsMock.sqrt(*) wasCalled once
    }
  }
}

希望这是有意义的,你提到你是scala新手,所以我不想对隐式太疯狂,所以这是一个非常基本的示例,其中原始Operations类的API是相同的,但它将繁重的工作提取给了第三方,可以模仿,这样你就可以验证交互了。

我试着退一步,您想要测试这些方法相互调用的次数的原因是什么?假设您必须处理一个非常大的列表,并且如果您调用了更高级别的函数,您的代码应该能够重用您所做的任何计算。例如,如果先调用z,然后调用x,则代码不应进行任何重新计算。我希望我的测试用例总是检查这种行为以保证这种性能。谢谢你的建议,这看起来像我需要的,但我不知道smarkMock是从哪里来的。还有一个有点相切的问题。我在几个例子中注意到了语法mock[className],但是当类的默认构造函数需要参数时会发生什么呢?当minObject.getAttributesearch.thenReturnsomeObject确保您接受问题的答案时,您也会模拟它。这正是我要找的,但我似乎无法得到sum*,被调用,一次去上班。我尝试使用Mockito.spy,但当我使用星号或尝试调用wasCalled时,它无法解决符号错误。这些方法来自不同的包吗?是的,mockito scala将您完全从mockito core抽象出来,因此您不应该使用org.mockito.mockito对象或任何其他core/java类,mockito scala中的模式类似于scalatest,您混合了所需的特性我已经更新了示例来说明这一点。如果解决了问题,请考虑将答案标记为正确答案:
var listoperations:Ops = new Ops(List(2,4,4))
listoperations.y // confirms 36 is return, confirms square and sum methods were called just once
listoperations.x // confirms List(4,16,16) and confirms square method was not called
listoperations.z // confirms 6 is returned and sqrt method called once and square and sum methods were not called.
class NumberOPSTest extends FunSuite with Matchers with Mockito {

  test("testSum") {
    val listoperations = smartMock[NumberOPS]
    when(listoperations.sum(any)).thenCallRealMethod()

    listoperations.sum(List(2, 4, 4)) shouldEqual 10

    verify(listoperations, never()).sqrt(any)
  }

}
class Ops {
 def square(numbers: List[Int]): List[Int] = numbers.map(n => n*n)
 def sum(numbers: List[Int]): Int = numbers.sum
 def sqrt(num: Int): Double = scala.math.sqrt(num)
}

class Operations(nums: List[Int])(implicit ops: Ops) {
 lazy val x: List[Int] = ops.square(nums)
 lazy val y: Int = ops.sum(x)
 lazy val z: Double = ops.sqrt(y)
}

import org.mockito.{ ArgumentMatchersSugar, IdiomaticMockito}

class IdiomaticMockitoTest extends AnyWordSpec with IdiomaticMockito with ArgumentMatchersSugar
  "operations" should {
    "be memoised" in {
      implicit val opsMock = spy(new Ops)
      val testObj = new Operations(List(2, 4, 4))

      testObj.x shouldBe List(4, 16, 16)
      testObj.y shouldBe 36
      testObj.y shouldBe 36 //call it again just for the sake of the argument
      testObj.z shouldBe 6 //sqrt(36)
      testObj.z shouldBe 6 //sqrt(36), call it again just for the sake of the argument

      opsMock.sum(*) wasCalled once
      opsMock.sqrt(*) wasCalled once
    }
  }
}