【发布时间】:2020-03-06 10:59:30
【问题描述】:
假设我有一个将读取操作包装在 Try 块中的特征:
import scala.util.Try
trait ReadingProvider[T] {
def readTable(tableName: String):Try[T]
}
也是一个提供使用 spark 读取的方法的类和一个用于从故障中恢复的方法的隐式类
import org.apache.spark.sql._
import org.apache.spark.sql.types.StructType
import scala.util.{Try, Success, Failure}
class SparkReadingProvider(spark: SparkSession) extends ReadingProvider[DataFrame] {
override readTable: Try[DataFrame] = Try(spark.read.table(tableName))
def createEmptyDF(schema: StructType): DataFrame =spark.createDataFrame(spark.sparkContext.emptyRDD[Row], schema)
}
implicit class ReadingHandler(tryDF: Try[DataFrame]) {
def recoverWithEmptyDF(schema: StructType): DataFrame = tryDF match {
case Failure(ex) => //Log something
createEmptyDF(schema)
case Success(df) => //Log something
df
}
}
}
现在我有一个包含阅读和一些转换的对象:
object MyObject {
def readSomeTable(tableName): SparkReadingProvider => DataFrame = provider => {
import provider.ReadingHandler
provider.readTable(tableName).recoverWithEmptyDF
}
def transform: DataFrame => DataFrame = ???
def mainMethod(tableName)(implicit val provider: SparkReadingProvider): DataFrame =
readSomeTable(tableName) andThen transform apply provider
}
我想对MyObject 中的方法进行单元测试。我不想使用真实的文件或表格,因此我的目标是使用模拟。
在我的测试中,我试图模拟 SparkReadingProvider:
describe("reading") {
it("should return empty dataframe when reading failed") {
val provider: SparkReadingProvider = mock[SparkReadingProvider]
val tableName: String = "no_table"
provider.readTable _ expects tableName returning Failure(new Exception("Table does not exist"))
MyObject.readSomeTable(tableName) shouldBe empty
}
}
但是它失败并出现错误:
意外调用:
SparkReadingProvider.ReaderHandler(Failure(java.lang.Exception: 表不存在)) 预期: inAnyOrder { SparkReadingProvider.readTable(no_table) 一次(调用一次) }
实际: SparkReadingProvider.readTable(no_table) SparkReadingProvider.ReaderHandler(Failure(java.lang.Exception: 表不存在))
我的问题是:
- 是否可以在当前设置中实现我想要的?
- 如果没有,我应该如何重构我的代码
- 如果我在不同的类中测试隐式类中可用的方法,那么在
MyObject中测试readSomeTable和mainMethod是否有意义?
【问题讨论】:
标签: scala unit-testing apache-spark mocking scalamock