在scalatest中导入隐式方法

时间:2016-08-29 15:29:50

标签: scala implicit scalatest

我正在努力理解为什么隐式导入不能像我期望的那样工作。简化的失败示例(使用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特性在beforeAllafterAll中创建并销毁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?

1 个答案:

答案 0 :(得分:1)

beforeAll在任何测试之前运行,但不在类的构造函数之前运行。第一个代码段中的操作顺序为:

  1. 调用构造函数,执行val testSqlctx = sqlctximport sqlctx.implicits._

  2. beforeAll已调用

  3. 测试运行

  4. 第二个片段的操作顺序:

    1. beforeAll已调用

    2. 测试运行,执行val testSqlctx = sqlctximport sqlctx.implicits._

    3. 假设您为SparkContext提供了默认值(null)并在beforeAll中对其进行了初始化,那么第一个操作顺序会在sqlctx仍在使用null2016-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) ,从而导致空指针异常。