使用FunSuite测试Spark会抛出NullPointerException

时间:2014-10-02 23:01:46

标签: scala apache-spark scalatest

我想使用FunSuite来测试我的Spark作业,方法是使用名为localTest的新函数扩展FunSuite,该函数使用默认的SparkContext运行测试:

class SparkFunSuite extends FunSuite {

  def localTest(name : String)(f : SparkContext => Unit) : Unit = {
    val conf = new SparkConf().setAppName(name).setMaster("local")
    val sc = new SparkContext(conf)
    try {
      this.test(name)(f(sc))
    } finally {
      sc.stop
    }
  }
}

然后我可以轻松地将测试添加到我的测试套件中:

class MyTestSuite extends SparkFunSuite {

  localTest("My Spark test") { sc =>
    assertResult(2)(sc.parallelize(Seq(1,2,3)).filter(_ <= 2).map(_ + 1).count)
  }
}

问题在于,当我运行测试时,我得到NullPointerException

[info] MyTestSuite:
[info] - My Spark test *** FAILED ***
[info]   java.lang.NullPointerException:
[info]   at org.apache.spark.SparkContext.defaultParallelism(SparkContext.scala:1215)
[info]   at org.apache.spark.SparkContext.parallelize$default$2(SparkContext.scala:435)
[info]   at MyTestSuite$$anonfun$1.apply(FunSuiteTest.scala:24)
[info]   at MyTestSuite$$anonfun$1.apply(FunSuiteTest.scala:23)
[info]   at SparkFunSuite$$anonfun$localTest$1.apply$mcV$sp(FunSuiteTest.scala:13)
[info]   at SparkFunSuite$$anonfun$localTest$1.apply(FunSuiteTest.scala:13)
[info]   at SparkFunSuite$$anonfun$localTest$1.apply(FunSuiteTest.scala:13)
[info]   at org.scalatest.Transformer$$anonfun$apply$1.apply$mcV$sp(Transformer.scala:22)
[info]   at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
[info]   at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
[info]   ...

导致NullPointerException的原因是什么?我在这种情况下使用Spark的方式不正确吗?

我将Scala 2.10.4与spark-core 1.0.2和scalatest 2.2.2一起使用。

2 个答案:

答案 0 :(得分:4)

如果您在多个类中运行SparkContexts,请确保将parallelExecution in Test := false放在build.sbt中。我在运行命令时遇到了问题:sbt test。我会得到由JVM中运行的多个SparkContexts引起的NPEPARSING_ERROR

答案 1 :(得分:1)

这不起作用的原因是我误用了FunSuite.test。此方法在调用时注册新测试,即构造FunSuite时。然后在运行测试时调用测试。但我的localTest会在调用FunSuite.test之前和之后执行一些操作。特别是,在使用this.test(name)(f(sc))注册测试后,它会停止SparkContext。调用测试时,sc将停止,并导致NullPointerException taskScheduler字段SparkContxt。使用FunSuite的正确方法是:

import org.scalatest.FunSuite

import org.apache.spark.SparkConf
import org.apache.spark.SparkContext


class SparkFunSuite extends FunSuite {

  def localTest(name : String)(f : SparkContext => Unit) : Unit = {
    this.test(name) {
      val conf = new SparkConf()
        .setAppName(name)
        .setMaster("local")
        .set("spark.default.parallelism", "1")
      val sc = new SparkContext(conf)
      try {
        f(sc)
      } finally {
        sc.stop()
      }
    }
  }

}

class MyTestSuite extends SparkFunSuite {

  localTest("My Spark test") { sc =>
    assertResult(2)(sc.parallelize(Seq(1,2,3)).filter(_ <= 2).map(_ + 1).count)
  }
}