我正在努力理解为什么隐式导入不能像我期望的那样工作 . 简化的失败示例(使用spark,但我也可以使用我的自定义类失败)如下:
class FailingSpec extends FlatSpec with Matchers with MySparkContext {
val testSqlctx = sqlctx
import sqlctx.implicits._
"sql context implicts" should "work" in {
val failingDf = Seq(ID(1)).toDS.toDF
}
}
MySparkContext特性在 beforeAll
和 afterAll
中创建并销毁火花上下文,并使 sqlctx
可用(已经必须将其重新分配给局部变量以便导入含义是一个难题,但可能在不同的时间) . 然后 .toDS
和 .toDF
是从 sqlctx.implicits
导入的隐式方法 . 运行测试结果 java.lang.NullPointerException
.
如果我将导入移动到测试块的工作:
class WorkingSpec extends FlatSpec with Matchers with MySparkContext {
"sql context implicts" should "work" in {
val testSqlctx = sqlctx
import sqlctx.implicits._
val workingDf = Seq(ID(1)).toDS.toDF
}
}
任何想法为什么我不能在测试类的顶层导入implicits?
1 回答
beforeAll
在任何测试之前运行,但不在类的构造函数之前运行 . 第一个代码段中的操作顺序是:调用构造函数,执行
val testSqlctx = sqlctx
和import sqlctx.implicits._
beforeAll
被调用测试运行
以及第二个代码段的操作顺序:
beforeAll
被调用测试运行,执行
val testSqlctx = sqlctx
和import sqlctx.implicits._
假设您给
SparkContext
一个默认值(null
)并在beforeAll
初始化它,第一个操作顺序将尝试使用sqlctx
,当它仍然是null
时,从而导致空指针异常 .