Làm cách nào để viết các bài kiểm tra đơn vị trong Spark 2.0+?


78

Tôi đã cố gắng tìm một cách hợp lý để kiểm tra SparkSessionvới khung kiểm tra JUnit. Mặc dù có vẻ là những ví dụ tốt cho SparkContext, nhưng tôi không thể tìm ra cách để có được một ví dụ tương ứng hoạt động SparkSession, mặc dù nó được sử dụng ở một số nơi trong nội bộ cơ sở thử nghiệm tia lửa . Tôi rất vui khi thử một giải pháp không sử dụng cơ sở thử nghiệm tia lửa nếu nó thực sự không phải là cách phù hợp để đi đến đây.

Trường hợp thử nghiệm đơn giản ( hoàn thành dự án MWE với build.sbt):

import com.holdenkarau.spark.testing.DataFrameSuiteBase
import org.junit.Test
import org.scalatest.FunSuite

import org.apache.spark.sql.SparkSession


class SessionTest extends FunSuite with DataFrameSuiteBase {

  implicit val sparkImpl: SparkSession = spark

  @Test
  def simpleLookupTest {

    val homeDir = System.getProperty("user.home")
    val training = spark.read.format("libsvm")
      .load(s"$homeDir\\Documents\\GitHub\\sample_linear_regression_data.txt")
    println("completed simple lookup test")
  }

}

Kết quả của việc chạy điều này với JUnit là một NPE ở dòng tải:

java.lang.NullPointerException
    at SessionTest.simpleLookupTest(SessionTest.scala:16)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Lưu ý rằng tệp đang được tải có tồn tại hay không không quan trọng; trong một SparkSession được định cấu hình đúng cách, một lỗi hợp lý hơn sẽ được đưa ra .


1
Cảm ơn tất cả các phản hồi cho đến nay; Tôi hy vọng sẽ xem xét sớm. Tôi cũng đã mở ra một vấn đề và đang tham khảo chéo nó tại đây: github.com/holdenk/spark-testing-base/issues/180
bbarker

Thật không may, tôi vẫn chưa thực sự sử dụng Spark ... một ngày nào đó, có thể là 3.x với tốc độ này - nếu không, tôi sẽ cố gắng chấp nhận câu trả lời. Rất vui vì điều này đã hữu ích cho những người khác.
bbarker

Câu trả lời:


112

Cảm ơn bạn đã đặt câu hỏi nổi bật này ra khỏi đó. Vì một lý do nào đó, khi nhắc đến Spark, mọi người đều bị cuốn vào phân tích đến nỗi họ quên mất các phương pháp kỹ thuật phần mềm tuyệt vời đã xuất hiện trong 15 năm qua. Đây là lý do tại sao chúng ta nên thảo luận về thử nghiệm và tích hợp liên tục (trong số những thứ khác như DevOps) trong khóa học của mình.

Sơ lược về thuật ngữ

A bài kiểm tra đơn vị thực sự có nghĩa là bạn có toàn quyền kiểm soát mọi thành phần trong bài kiểm tra. Không thể có tương tác với cơ sở dữ liệu, cuộc gọi REST, hệ thống tệp hoặc thậm chí là đồng hồ hệ thống; mọi thứ phải được "nhân đôi" (ví dụ: chế nhạo, khai thác, v.v.) như Gerard Mezaros đưa nó vào Mẫu thử nghiệm xUnit . Tôi biết điều này có vẻ giống như ngữ nghĩa, nhưng nó thực sự quan trọng. Không hiểu đây là một trong những lý do chính khiến bạn thấy các lỗi kiểm tra không liên tục trong tích hợp liên tục.

Chúng tôi vẫn có thể kiểm tra đơn vị

Vì vậy, với sự hiểu biết này, kiểm tra đơn vị một RDDlà không thể. Tuy nhiên, vẫn có một nơi để kiểm thử đơn vị khi phát triển phân tích.

Hãy xem xét một hoạt động đơn giản:

rdd.map(foo).map(bar)

Đây foobarlà các chức năng đơn giản. Chúng có thể được kiểm tra đơn vị theo cách thông thường, và chúng phải được với nhiều trường hợp góc nhất bạn có thể tập hợp. Rốt cuộc, tại sao họ lại quan tâm đến việc họ lấy đầu vào từ đâu cho dù đó là vật cố định thử nghiệm hay vật phẩm RDD?

Đừng quên Spark Shell

Đây không phải là thử nghiệm cho mỗi người , nhưng trong những giai đoạn đầu này, bạn cũng nên thử nghiệm trong Spark shell để tìm ra các chuyển đổi của bạn và đặc biệt là hậu quả của cách tiếp cận của bạn. Ví dụ, bạn có thể kiểm tra kế hoạch truy vấn vật lý và logic, phân vùng chiến lược và bảo quản, và tình trạng của dữ liệu của bạn với nhiều chức năng khác nhau như toDebugString, explain, glom, show, printSchema, và vân vân. Tôi sẽ cho bạn khám phá những điều đó.

Bạn cũng có thể đặt chủ của mình thành local[2] trong Spark shell và trong các thử nghiệm của mình để xác định bất kỳ vấn đề nào chỉ có thể phát sinh khi bạn bắt đầu phân phối công việc.

Kiểm tra tích hợp với Spark

Bây giờ cho các công cụ thú vị.

Để kiểm tra tích hợp Spark sau khi bạn cảm thấy tin tưởng vào chất lượng của các chức năng trợ giúp và RDD/ DataFramelogic chuyển đổi của mình, điều quan trọng là phải thực hiện một số điều (bất kể công cụ xây dựng và khung kiểm tra):

  • Tăng bộ nhớ JVM.
  • Bật phân tách nhưng vô hiệu hóa thực thi song song.
  • Sử dụng khung thử nghiệm của bạn để tích lũy các bài kiểm tra tích hợp Spark của bạn thành các bộ và khởi tạo SparkContexttrước tất cả các bài kiểm tra và dừng nó sau tất cả các bài kiểm tra.

Với ScalaTest, bạn có thể trộn vào BeforeAndAfterAll(mà tôi thường thích hơn) hoặc BeforeAndAfterEachnhư @ShankarKoirala làm để khởi tạo và chia nhỏ các tạo tác Spark. Tôi biết đây là một nơi hợp lý để tạo một ngoại lệ, nhưng tôi thực sự không thích những thứ có thể thay đổi varmà bạn phải sử dụng.

Mô hình cho vay

Một cách tiếp cận khác là sử dụng Mô hình Khoản vay .

Ví dụ (sử dụng ScalaTest):

class MySpec extends WordSpec with Matchers with SparkContextSetup {
  "My analytics" should {
    "calculate the right thing" in withSparkContext { (sparkContext) =>
      val data = Seq(...)
      val rdd = sparkContext.parallelize(data)
      val total = rdd.map(...).filter(...).map(...).reduce(_ + _)

      total shouldBe 1000
    }
  }
}

trait SparkContextSetup {
  def withSparkContext(testMethod: (SparkContext) => Any) {
    val conf = new SparkConf()
      .setMaster("local")
      .setAppName("Spark test")
    val sparkContext = new SparkContext(conf)
    try {
      testMethod(sparkContext)
    }
    finally sparkContext.stop()
  }
} 

Như bạn có thể thấy, Mô hình Khoản vay sử dụng các chức năng bậc cao hơn để "cho mượn" SparkContextbài kiểm tra và sau đó loại bỏ nó sau khi hoàn thành.

Lập trình định hướng đau khổ (Cảm ơn, Nathan)

Đó hoàn toàn là vấn đề sở thích, nhưng tôi thích sử dụng Mô hình Khoản vay và tự sắp xếp mọi thứ miễn là có thể trước khi đưa vào một khuôn khổ khác. Bên cạnh việc cố gắng duy trì dung lượng nhẹ, các khung công tác đôi khi thêm rất nhiều "phép thuật" khiến cho việc gỡ lỗi kiểm tra thất bại trở nên khó giải thích. Vì vậy, tôi tham gia chương trình Định hướng đau khổ phương pháp - nơi tôi tránh thêm một khung công tác mới cho đến khi nỗi đau không có nó là quá sức chịu đựng. Nhưng một lần nữa, điều này là vào bạn.

Sự lựa chọn tốt nhất cho khung thay thế đó tất nhiên là cơ sở thử nghiệm tia lửa như @ShankarKoirala đã đề cập. Trong trường hợp đó, kiểm tra ở trên sẽ giống như sau:

class MySpec extends WordSpec with Matchers with SharedSparkContext {
      "My analytics" should {
        "calculate the right thing" in { 
          val data = Seq(...)
          val rdd = sc.parallelize(data)
          val total = rdd.map(...).filter(...).map(...).reduce(_ + _)

          total shouldBe 1000
        }
      }
 }

Lưu ý rằng tôi không phải làm gì để đối phó với SparkContext. SharedSparkContextđã cho tôi tất cả những gì - với scnhưSparkContext miễn phí. Cá nhân tôi mặc dù tôi sẽ không mang lại sự phụ thuộc này chỉ cho mục đích này vì Mô hình Khoản vay thực hiện chính xác những gì tôi cần cho điều đó. Ngoài ra, với rất nhiều điều không thể đoán trước xảy ra với các hệ thống phân tán, có thể là một nỗi đau thực sự khi phải truy tìm phép thuật xảy ra trong mã nguồn của thư viện bên thứ ba khi mọi thứ xảy ra sai trong quá trình tích hợp liên tục.

Giờ đây, nơi cơ sở thử nghiệm tia lửa thực sự tỏa sáng là với những người trợ giúp dựa trên Hadoop như HDFSClusterLikeYARNClusterLike . Kết hợp những đặc điểm đó thực sự có thể giúp bạn tiết kiệm rất nhiều công sức khi thiết lập. Một nơi khác mà nó tỏa sáng là với các thuộc tính và trình tạo giống như Scalacheck - tất nhiên giả sử bạn hiểu cách kiểm tra dựa trên thuộc tính hoạt động và tại sao nó lại hữu ích. Nhưng một lần nữa, cá nhân tôi sẽ ngừng sử dụng nó cho đến khi các phép phân tích và thử nghiệm của tôi đạt đến mức độ tinh vi đó.

"Chỉ có một người Sith giải quyết sự tuyệt đối." - Obi-Wan Kenobi

Tất nhiên, bạn không cần phải chọn cái này hay cái kia. Có lẽ bạn có thể sử dụng phương pháp Mô hình Khoản vay cho hầu hết các thử nghiệm của mình và cơ sở thử nghiệm tia lửa chỉ cho một số thử nghiệm nghiêm ngặt hơn. Sự lựa chọn không phải là nhị phân; bạn có thể làm cả hai.

Kiểm tra tích hợp với Spark Streaming

Cuối cùng, tôi chỉ muốn trình bày một đoạn mã về thiết lập kiểm tra tích hợp SparkStreaming với các giá trị trong bộ nhớ có thể trông như thế nào mà không có cơ sở kiểm tra tia lửa :

val sparkContext: SparkContext = ...
val data: Seq[(String, String)] = Seq(("a", "1"), ("b", "2"), ("c", "3"))
val rdd: RDD[(String, String)] = sparkContext.parallelize(data)
val strings: mutable.Queue[RDD[(String, String)]] = mutable.Queue.empty[RDD[(String, String)]]
val streamingContext = new StreamingContext(sparkContext, Seconds(1))
val dStream: InputDStream = streamingContext.queueStream(strings)
strings += rdd

Điều này đơn giản hơn vẻ ngoài của nó. Nó thực sự chỉ biến một chuỗi dữ liệu thành một hàng đợi để cấp dữ liệu cho DStream. Hầu hết nó thực sự chỉ là thiết lập bảng soạn sẵn hoạt động với các API Spark. Bất kể, bạn có thể so sánh điều này với StreamingSuiteBase như được tìm thấy trong cơ sở thử nghiệm tia lửa để quyết định bạn thích cái nào hơn.

Đây có thể là bài viết dài nhất của tôi từ trước đến nay, vì vậy tôi sẽ để nó ở đây. Tôi hy vọng những người khác đồng tình với những ý tưởng khác để giúp cải thiện chất lượng phân tích của chúng tôi với cùng các phương pháp kỹ thuật phần mềm linh hoạt đã cải thiện tất cả các phát triển ứng dụng khác.

Và với những lời xin lỗi vì cái phích cắm vô liêm sỉ, bạn có thể xem khóa học Analytics của chúng tôi với Apache Spark , nơi chúng tôi giải quyết rất nhiều ý tưởng này và hơn thế nữa. Chúng tôi hy vọng sẽ sớm có phiên bản trực tuyến.


2
Cảm ơn cho bản viết chi tiết này. Ước gì tôi có thể cho bạn nhiều hơn một phiếu ủng hộ.
user1452132

1
Cảm ơn bạn. Điều đó thật là tốt. Tôi hy vọng câu trả lời giúp bạn với dự án hoặc sự hiểu biết của bạn.
Vidya

27

Bạn có thể viết một bài kiểm tra đơn giản với FunSuite và BeforeAndAfterEach như bên dưới

class Tests extends FunSuite with BeforeAndAfterEach {

  var sparkSession : SparkSession = _
  override def beforeEach() {
    sparkSession = SparkSession.builder().appName("udf testings")
      .master("local")
      .config("", "")
      .getOrCreate()
  }

  test("your test name here"){
    //your unit test assert here like below
    assert("True".toLowerCase == "true")
  }

  override def afterEach() {
    sparkSession.stop()
  }
}

Bạn không cần phải tạo một hàm trong thử nghiệm, bạn có thể chỉ cần viết là

test ("test name") {//implementation and assert}

Holden Karau đã viết bài kiểm tra rất hay cơ sở tia lửa thử nghiệm rất hay

Bạn cần xem dưới đây là một ví dụ đơn giản

class TestSharedSparkContext extends FunSuite with SharedSparkContext {

  val expectedResult = List(("a", 3),("b", 2),("c", 4))

  test("Word counts should be equal to expected") {
    verifyWordCount(Seq("c a a b a c b c c"))
  }

  def verifyWordCount(seq: Seq[String]): Unit = {
    assertResult(expectedResult)(new WordCount().transform(sc.makeRDD(seq)).collect().toList)
  }
}

Hi vọng điêu nay co ich!


Câu trả lời chính xác. Đặc điểm kỹ thuật tia lửa đã sử dụng một cách tiếp cận tương tự, nhưng quá chậm khi nhiều tệp thử nghiệm được thêm vào dự án. Hãy xem câu trả lời của tôi để biết cách triển khai thay thế không buộc dừng / khởi động SparkSession sau mỗi tệp thử nghiệm.
Quyền hạn

2
Tôi cũng thích phần đầu tiên của câu trả lời này; Tôi chỉ ước ví dụ thứ hai có thứ Spark trong đó thay vì khẳng định đồ chơi. Ngoài ra, tôi sẽ chỉ ra rằng khái niệm thực hiện hiệu quả phụ đắt tiền trước và / hoặc sau một bộ thử nghiệm không phải là một ý tưởng mới. Như tôi đề xuất trong câu trả lời của mình, ScalaTest có rất nhiều cơ chế cho điều đó - trong trường hợp này là để quản lý các đồ tạo tác Spark - và bạn có thể sử dụng chúng như cách bạn làm cho bất kỳ đồ đạc đắt tiền nào khác. Ít nhất là cho đến thời điểm mà việc mang lại một khuôn khổ bên thứ ba nặng hơn là đáng giá.
Vidya

Một lưu ý nhỏ là ScalaTest và specs2 (mà tôi nghĩ là làm như vậy theo mặc định) đều có thể chạy các bài kiểm tra song song để tăng tốc độ. Các công cụ xây dựng cũng có thể hữu ích. Nhưng một lần nữa, không có điều nào trong số này là mới.
Vidya

Tôi đã chỉnh sửa ví dụ thử nghiệm thích hợp cho cơ sở thử nghiệm tia lửa theo đề xuất của bạn. Cảm ơn,
koiralo

17

Kể từ Spark 1.6 bạn có thể sử dụng SharedSparkContexthoặc SharedSQLContextSpark sử dụng cho các bài kiểm tra đơn vị của riêng nó:

class YourAppTest extends SharedSQLContext {

  var app: YourApp = _

  protected override def beforeAll(): Unit = {
    super.beforeAll()

    app = new YourApp
  }

  protected override def afterAll(): Unit = {
    super.afterAll()
  }

  test("Your test") {
    val df = sqlContext.read.json("examples/src/main/resources/people.json")

    app.run(df)
  }

Spark 2.3 SharedSparkSession có sẵn:

class YourAppTest extends SharedSparkSession {

  var app: YourApp = _

  protected override def beforeAll(): Unit = {
    super.beforeAll()

    app = new YourApp
  }

  protected override def afterAll(): Unit = {
    super.afterAll()
  }

  test("Your test") {
    df = spark.read.json("examples/src/main/resources/people.json")

    app.run(df)
  }

CẬP NHẬT:

Maven phụ thuộc:

<dependency>
  <groupId>org.scalactic</groupId>
  <artifactId>scalactic</artifactId>
  <version>SCALATEST_VERSION</version>
</dependency>
<dependency>
  <groupId>org.scalatest</groupId>
  <artifactId>scalatest</artifactId>
  <version>SCALATEST_VERSION</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.apache.spark</groupId>
  <artifactId>spark-core</artifactId>
  <version>SPARK_VERSION</version>
  <type>test-jar</type>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.apache.spark</groupId>
  <artifactId>spark-sql</artifactId>
  <version>SPARK_VERSION</version>
  <type>test-jar</type>
  <scope>test</scope>
</dependency>

SBT phụ thuộc:

"org.scalactic" %% "scalactic" % SCALATEST_VERSION
"org.scalatest" %% "scalatest" % SCALATEST_VERSION % "test"
"org.apache.spark" %% "spark-core" % SPARK_VERSION % Test classifier "tests"
"org.apache.spark" %% "spark-sql" % SPARK_VERSION % Test classifier "tests"

Ngoài ra, bạn có thể kiểm tra các nguồn thử nghiệm của Spark nơi có rất nhiều bộ thử nghiệm khác nhau.

CẬP NHẬT 2:

Apache Spark Unit Testing Part 1 - Các thành phần cốt lõi

Apache Spark Unit Testing Part 2 - Spark SQL

Apache Spark Unit Testing Part 3 - Streaming

Kiểm tra tích hợp Apache Spark


1
bạn có biết gói maven nào chứa lớp này không?
James Gan

Tất nhiên. Cả hai của nó trong"org.apache.spark" %% "spark-sql" % SPARK_VERSION % Test classifier "tests"
Eugene Lopatkin

Đối với Maven<dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-sql</artifactId> <version>SPARK_VERSION</version> <type>test-jar</type> <scope>test</scope> </dependency>
Eugene Lopatkin

4
Đối với tôi, cũng cần bổ sung các nguồn lõi tia lửa và chất xúc tác tia lửa vớilibraryDependencies += "org.apache.spark" %% "spark-core" % SPARK_VERSION withSources() libraryDependencies += "org.apache.spark" %% "spark-catalyst" % SPARK_VERSION withSources()
rad i.

Chúc một ngày tốt lành, Huang! Ý bạn là gì về "Không thể giải quyết kiểm tra biểu tượng"? Nó đã xảy ra ở đâu?
Eugene Lopatkin

13

Tôi muốn tạo ra một SparkSessionTestWrapperđặc điểm có thể trộn lẫn vào các lớp thử nghiệm. Phương pháp của Shankar hoạt động, nhưng nó cực kỳ chậm đối với các bộ thử nghiệm có nhiều tệp.

import org.apache.spark.sql.SparkSession

trait SparkSessionTestWrapper {

  lazy val spark: SparkSession = {
    SparkSession.builder().master("local").appName("spark session").getOrCreate()
  }

}

Đặc điểm có thể được sử dụng như sau:

class DatasetSpec extends FunSpec with SparkSessionTestWrapper {

  import spark.implicits._

  describe("#count") {

    it("returns a count of all the rows in a DataFrame") {

      val sourceDF = Seq(
        ("jets"),
        ("barcelona")
      ).toDF("team")

      assert(sourceDF.count === 2)

    }

  }

}

Kiểm tra dự án spark-spec để biết ví dụ thực tế sử dụng SparkSessionTestWrapperphương pháp này.

Cập nhật

Các thư viện spark-thử nghiệm-base tự động thêm SparkSession khi những đặc điểm nhất định được trộn lẫn vào lớp thử nghiệm (ví dụ như khi DataFrameSuiteBaseđược trộn lẫn trong, bạn sẽ có quyền truy cập vào các SparkSession quaspark biến).

Tôi đã tạo một thư viện thử nghiệm riêng biệt có tên là spark-fast-tests để cung cấp cho người dùng toàn quyền kiểm soát SparkSession khi chạy thử nghiệm của họ. Tôi không nghĩ rằng một thư viện trình trợ giúp kiểm tra nên đặt SparkSession. Người dùng sẽ có thể bắt đầu và dừng SparkSession của họ khi họ thấy phù hợp (tôi muốn tạo một SparkSession và sử dụng nó trong suốt quá trình chạy bộ thử nghiệm).

Dưới đây là một ví dụ về assertSmallDatasetEqualityphương pháp kiểm tra nhanh tia lửa đang hoạt động:

import com.github.mrpowers.spark.fast.tests.DatasetComparer

class DatasetSpec extends FunSpec with SparkSessionTestWrapper with DatasetComparer {

  import spark.implicits._

    it("aliases a DataFrame") {

      val sourceDF = Seq(
        ("jose"),
        ("li"),
        ("luisa")
      ).toDF("name")

      val actualDF = sourceDF.select(col("name").alias("student"))

      val expectedDF = Seq(
        ("jose"),
        ("li"),
        ("luisa")
      ).toDF("student")

      assertSmallDatasetEquality(actualDF, expectedDF)

    }

  }

}

1
Trong cách tiếp cận này, làm thế nào bạn khuyên bạn nên thêm sparkSession.stop()một nơi nào đó?
Neil Best

Bạn không cần phải sparkSession.stop()@NeilBest. Phiên Spark sẽ bị tắt khi bộ thử nghiệm chạy xong.
Quyền hạn

1
tại sao không cần phải sparkSession.stop ()? như câu trả lời của @Shankar Koirala ngăn chặn sparkSession, điều này có vô ích không?
yuxh

@yuxh - Câu trả lời của Shankar bắt đầu và dừng phiên Spark sau mỗi bài kiểm tra. Cách tiếp cận này hoạt động, nhưng nó thực sự chậm vì phải mất một lúc để bắt đầu một phiên Spark.
Quyền hạn

1
nhưng anh ấy cũng đề cập đến spark-testing-base, SharedSparkContext dừng bối cảnh này sau tất cả các trường hợp thử nghiệm. Tôi không thấy bất kỳ mã dừng ngay cả sau khi tất cả các trường hợp thử nghiệm trong SparkSessionTestWrapper của bạn
yuxh

1

Tôi có thể giải quyết vấn đề với mã dưới đây

phụ thuộc spark-hive được thêm vào trong dự án pom

class DataFrameTest extends FunSuite with DataFrameSuiteBase{
        test("test dataframe"){
        val sparkSession=spark
        import sparkSession.implicits._
        var df=sparkSession.read.format("csv").load("path/to/csv")
        //rest of the operations.
        }
        }

0

Một cách khác để kiểm tra đơn vị bằng JUnit

import org.apache.spark.sql.SparkSession
import org.junit.Assert._
import org.junit.{After, Before, _}

@Test
class SessionSparkTest {
  var spark: SparkSession = _

  @Before
  def beforeFunction(): Unit = {
    //spark = SessionSpark.getSparkSession()
    spark = SparkSession.builder().appName("App Name").master("local").getOrCreate()
    System.out.println("Before Function")
  }

  @After
  def afterFunction(): Unit = {
    spark.stop()
    System.out.println("After Function")
  }

  @Test
  def testRddCount() = {
    val rdd = spark.sparkContext.parallelize(List(1, 2, 3))
    val count = rdd.count()
    assertTrue(3 == count)
  }

  @Test
  def testDfNotEmpty() = {
    val sqlContext = spark.sqlContext
    import sqlContext.implicits._
    val numDf = spark.sparkContext.parallelize(List(1, 2, 3)).toDF("nums")
    assertFalse(numDf.head(1).isEmpty)
  }

  @Test
  def testDfEmpty() = {
    val sqlContext = spark.sqlContext
    import sqlContext.implicits._
    val emptyDf = spark.sqlContext.createDataset(spark.sparkContext.emptyRDD[Num])
    assertTrue(emptyDf.head(1).isEmpty)
  }
}

case class Num(id: Int)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.