测试以确保两个功能可以同时运行?

时间:2019-05-25 16:43:27

标签: scala unit-testing concurrency

假设我有一个函数runConcurrently(f1: Int => Int, f2: Int => Int): (Int, Int),该函数返回f1f2的结果。

现在,我想编写一个测试以确保在调用f1f2runConcurrently同时运行 。我想使测试具有确定性并尽可能高效。

您如何建议编写测试?

P.S。我不想将其与任何特定的测试框架或库结合使用。唯一的依赖关系应该是Scala / Java SDK。

3 个答案:

答案 0 :(得分:5)

您能做的最接近的事情是使用两个函数都使用的某种共享条件:

def runConcurrently(f1: => Int, f2: => Int): Future[(Int, Int)] = 
   Future(f1) zip Future(f2)

 val sem1 = new Semaphore(0)
 val sem2 = new Semaphore(0)

 def f1 = {
    sem1.release
    sem2.acquire
    1
 }

 def f2 = {
    sem2.release
    sem1.acquire
    2
}

Await.result(runConcurrently(f1, f2), 1 second) shouldBe (1,2)

这个想法是,至少在另一个功能启动之前,这两个功能都无法完成。因此,按顺序运行它们的尝试将永远不会完成,并且您将超时。

尤其是,如果您尝试在单线程执行上下文中运行它,则此代码将失败。

答案 1 :(得分:0)

如前所述,这可能不会一直有效,也远不是确定性的。
但是,它可能会为您服务。

final class FunctionMeter[-I, +O](private[this] val underlying: I => O) {
  private[this] var start: Long = _
  private[this] var finish: Long = _

  def getStartTime: Long = start
  def getFinishTime: Long = finish

  def getFun: I => O = input => {
    start = System.nanoTime()
    val output = underlying(input)
    finish = System.nanoTime()
    output
  }
}

def test(f1: Int => Int, f2: Int => Int): Boolean {
  val m1 = new FunctionMeter(f1)
  val m2 = new FunctionMeter(f2)

  runConcurrently(m1.getFunction, m2.getFunction)

  m2.getStartTime < m1.getFinishTime && m1.getStartTime < m2.getFinishTime
}

无论如何,我和Dima在一起,这不是您应该测试的东西。

答案 2 :(得分:-1)

一个丑陋问题的丑陋解决方案:

object Test extends App {
  def runConcurrently(f1: () => Int, f2: () => Int): (Int, Int) = {
    import ExecutionContext.Implicits.global
    val f = Future(f1())
    val g = Future(f2())
    Await.result(f.zip(g), Duration.Inf)
  }

  @volatile var start1: Long = 0
  @volatile var start2: Long = 0
  @volatile var end1: Long = 0
  @volatile var end2: Long = 0

  val f1 : () => Int = {
    case x : Unit => {
      start1 = System.nanoTime()
      Thread.sleep(1000)
      end1 = System.nanoTime()
      1
    }
  }

  val f2 : () => Int = {
    case x : Unit => {
      start2 = System.nanoTime()
      Thread.sleep(1000)
      end2 = System.nanoTime()
      1
    }
  }

  runConcurrently(f1, f2)

  assert(start1 < end2)
  assert(start2 < end1)

}