In the first part of this series we became familiar with ScalaTest. When it comes to unit test Scala Spark applications ScalaTest isn't enough: you need to add to the roster spark-testing-base. It is an Open Source framework which provides base classes for the main Spark abstractions like SparkContext, RDD, DataFrame, DataSet and Streaming. Let's start to explore all of the facilities provided by this framework and how it works along with ScalaTest with some simple examples. Let's consider the following Scala word count example found on the web:
This class expects a text file as input and first splits all of the words this contains and finally counts all of the occurrences for each one.
Add the ScalaTest dependency to sbt or Maven as described in the first part of this series. Then add the scala-testing-base dependency to sbt:
The code above is definitively not the best way to implement this class. Probably a better way (in terms of readability and maintenance) could be the following, implementing two separate methods (one for the mapping and one for the reduction by key):
Let's implement a test class for it now. We are going to combine ScalaTest and spark-testing-base together. Let's choose a ScalaTest style (for example FunSuite) and the SharedSparkContext trait:
SharedSparkContext initializes (before the tests start) and provides a SparkContext instance to be shared through all of the test in the class and stops it at the end of the test method execution. So no need to add extra code to initialize it and stop it. This way the development of a test class focuses only on the body of the test methods. For the class under test above is:
sc is the variable name of the built-in SparkContext provided by SharedSparkContext.
In the next post(s) we will walk through all of the other base classes provided by the spark-testing-base framework, starting from those related to RDDs.
import org.apache.spark.{SparkConf, SparkContext}
object SparkWordCount {
def main(args: Array[String]) {
val inputFile = args(0)
val outputFile = args(1)
val conf = new SparkConf().setAppName("
SparkWordCount
")
// Create a Scala Spark Context.
val sc = new SparkContext(conf)
// Load our input data.
val input = sc.textFile(inputFile)
// Split up into words.
val words = input.flatMap(line => line.split(" "))
// Transform into word and count.
val counts = words.map(word => (word, 1)).reduceByKey{case (x, y) => x + y}
// Save the word count back out to a text file, causing evaluation. counts.saveAsTextFile(outputFile)
}
}
This class expects a text file as input and first splits all of the words this contains and finally counts all of the occurrences for each one.
Add the ScalaTest dependency to sbt or Maven as described in the first part of this series. Then add the scala-testing-base dependency to sbt:
libraryDependencies += "com.holdenkarau" % "spark-testing-base_2.11" % "2.1.0_0.6.0"or Maven:
<
dependency
>
<
groupId
>com.holdenkarau</
groupId
>
<
artifactId
>spark-testing-base_2.11</
artifactId
>
<
version
>2.1.0_0.6.0</
version
>
</
dependency
>
The code above is definitively not the best way to implement this class. Probably a better way (in terms of readability and maintenance) could be the following, implementing two separate methods (one for the mapping and one for the reduction by key):
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD
object SparkWordCount {
def main(args: Array[String]) {
val conf = new SparkConf().setAppName("SparkWordCount")
val sc = new SparkContext(conf)
val file = sc.textFile(args(0))
countWordsInFile(file).saveAsTextFile(args(1))
}
def countWordsInFile = splitFile _ andThen countWords _
def splitFile(wordsByLine: RDD[String]): RDD[String] = {
wordsByLine.flatMap(line => line.split(" "))
}
def countWords(words: RDD[String]): RDD[(String, Int)] = {
words.map(word => (word, 1)).reduceByKey(_ + _)
}
}
Let's implement a test class for it now. We are going to combine ScalaTest and spark-testing-base together. Let's choose a ScalaTest style (for example FunSuite) and the SharedSparkContext trait:
class SparkWordCountScalaTestingBaseSuite extends FunSuite with SharedSparkContext
SharedSparkContext initializes (before the tests start) and provides a SparkContext instance to be shared through all of the test in the class and stops it at the end of the test method execution. So no need to add extra code to initialize it and stop it. This way the development of a test class focuses only on the body of the test methods. For the class under test above is:
val fileLines = Array("Line One", "Line Two", "Line Three", "Line Four")
test("splitFile should split the file into words"){
val inputRDD: RDD[String] = sc.parallelize[String](fileLines)
val wordsRDD = SparkWordCount.splitFile(inputRDD)
assert(wordsRDD.count() == 8)
}
test("countWordsInFile should count words") {
val inputRDD: RDD[String] = sc.parallelize[String](fileLines)
val results = SparkWordCount.countWordsInFile(inputRDD).collect
assert(results.contains(("Line", 4)))
}
sc is the variable name of the built-in SparkContext provided by SharedSparkContext.
In the next post(s) we will walk through all of the other base classes provided by the spark-testing-base framework, starting from those related to RDDs.
Really nice topics you had discussed above. I am much impressed. Thank you for providing this nice information here.
ReplyDeleteSoftware Testing Company
QA Services
XBOX Game Tester
Game Testing Companies
Console Game Testing
ReplyDeleteI was very interested in the article , it’s quite inspiring I should admit.
Selenium Training in Chennai | Certification | Online Courses
selenium training in chennai
selenium training in chennai
selenium online training in chennai
selenium training in bangalore
selenium training in hyderabad
selenium training in coimbatore
selenium online training
SAP BW on Hana training
ReplyDeletesap sd training
osb training
oracle scm training
abinitio training
Excellent article and this helps to enhance your knowledge regarding new things. Waiting for more updates.
ReplyDeleteAngular 11 New Features
Angular Latest Stable Version