我正在努力理解为什么隐式导入不能像我期望的那样工作。简化的失败示例(使用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
中创建并销毁spark上下文,并使sqlctx
可用(已经将其重新分配给局部变量以便导入implicits是一个难题,但也许是在不同的时间)。 .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?
答案 0 :(得分:1)
beforeAll
在任何测试之前运行,但不在类的构造函数之前运行。第一个代码段中的操作顺序为:
调用构造函数,执行val testSqlctx = sqlctx
和import sqlctx.implicits._
beforeAll
已调用
测试运行
第二个片段的操作顺序:
beforeAll
已调用
测试运行,执行val testSqlctx = sqlctx
和import sqlctx.implicits._
假设您为SparkContext
提供了默认值(null
)并在beforeAll
中对其进行了初始化,那么第一个操作顺序会在sqlctx
仍在使用null
时2016-08-29 16:51:08 [scrapy] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 896,
'downloader/request_count': 4,
'downloader/request_method_count/GET': 4,
'downloader/response_bytes': 35320,
'downloader/response_count': 4,
'downloader/response_status_count/200': 4,
'dupefilter/filtered': 149,
'finish_reason': 'finished',
'finish_time': datetime.datetime(2016, 8, 29, 16, 51, 8, 837853),
'log_count/DEBUG': 28,
'log_count/INFO': 7,
'offsite/domains': 22,
'offsite/filtered': 23,
'request_depth_max': 1,
'response_received_count': 4,
'scheduler/dequeued': 2,
'scheduler/dequeued/disk': 2,
'scheduler/enqueued': 2,
'scheduler/enqueued/disk': 2,
'start_time': datetime.datetime(2016, 8, 29, 16, 51, 7, 821974)}
2016-08-29 16:51:08 [scrapy] INFO: Spider closed (finished)
,从而导致空指针异常。