在运行 main 时通过反射获取 Scala 对象的实例,但在单元测试中失败,NoSuchFieldException: MODULE$

问题描述

我有用于运行 Spark 作业的 Scala 代码。在运行时,主类使用反射来加载抽象类的所有实现,这些实现可以作为火花作业运行,并根据命令行参数选择正确的实现,例如spark-submit etl.jar job-name-i-want-to-run。我正在运行 spark 3.0.1 和 Scala 2.12.10。当我尝试使用 spark-submit 运行它时,它工作得很好,但我尝试编写一个单元测试(使用 scalatest v3.2.2)并且它在 NoSuchFieldException 块上的 job.getField("MODULE$") 失败,用于子类SparkJobtest 文件夹内的包中声明。请注意,实现是在 object 中完成的,而不是在类中。所以我的问题是:为什么它对主文件夹中的子类有效,但对测试包中声明的子类无效(特别是仅用于测试此功能)?

import org.reflections.Reflections

object SparkJobLauncher {

  def runSparkJob(args: Array[String]): Unit = {
    val availableJobs = loadSparkJobs()
    availableJobs(args(0)).run(args)
  }

  private def loadSparkJobs(): Map[String,SparkJob] = {
      new Reflections("com.parent.package")
          .getSubTypesOf(classOf[SparkJob])
          .asScala
          .map(job => {
            val instance = job.getField("MODULE$").get(null).asInstanceOf[SparkJob]
            (instance.name,instance)
          })
          .filter(_ != null)
          .toMap
    }
}

SparkJob 抽象类的实现如下所示:

abstract class SparkJob {
  def name: String
  
  def run(args: Array[String]): Unit
  
  // ... other helper methods ...
}

一份工作可能是这样的:

object MyEtlJob extends SparkJob {
  override def name = "my-etl"
  override def run(args: Array[String]): Unit = {
    // do spark stuff...
  }
}

单元测试非常简单:

class SparkJobLauncherTest extends AnyFunSuite {

  test("Run job") {
    SparkJobLauncher.runSparkJob(Array("test"))
  }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)