■ はじめに
https://dk521123.hatenablog.com/entry/2023/03/27/001306
https://dk521123.hatenablog.com/entry/2023/03/28/003906
の続き。 今回は、Scalaの単体試験する際に ScalaTest を使用した時のTipsについてまとめる
目次
【1】初期処理・後処理 1)BeforeAndAfter 2)BeforeAndAfterAll 【2】一時的テストを停止する 1)テストメソッドを停止する 2)テストクラスを全体を停止する 【3】Public以外のメソッドのテスト 1)private メソッドをテストする 2)protected メソッドをテストする 【4】Table で色々なパターンの値を用意する 【5】例外処理をテストする 1)発生した例外を確認する 2)発生した例外+メッセージを確認する
【1】初期処理・後処理
1)BeforeAndAfter
* 各テスト前・後に呼び出されるメソッドを定義できる => 説明よりサンプルとログの出力結果みた方が分かりやすい
1)サンプル
package com.example import org.scalatest.funspec.AnyFunSpec import org.scalatest.BeforeAndAfter class HelloWorldTest extends AnyFunSpec with BeforeAndAfter { before { println("Before") // ★ログ } after { println("After") // ★ログ } describe("Hello World Test") { describe("Normal") { it("Set name=Mike") { println("Test1") // ☆ログ val result = HelloWorld.sayHello("Mike") assert(result == "Hello, Mike!!") } } describe("Abnormal") { it("should produce IllegalArgumentException when name is empty") { assertThrows[IllegalArgumentException] { println("Test2") // ☆ログ HelloWorld.sayHello("") } } } } }
出力結果
Before Test1 << 各テスト前に「Before」、後に「After」にCallする After Before Test2 << 各テスト前に「Before」、後に「After」にCallする After
2)BeforeAndAfterAll
* 1テスト前・後に呼び出されるメソッドを定義できる
サンプル
package com.example import org.scalatest.funspec.AnyFunSpec import org.scalatest.BeforeAndAfterAll class HelloWorldTest extends AnyFunSpec with BeforeAndAfterAll { override def beforeAll(): Unit = { println("beforeAll") } override def afterAll(): Unit = { println("afterAll") } // 略(上と同じ) }
出力結果
beforeAll Test1 Test2 afterAll
【2】一時的テストを停止する
* Ignore (無視)を指定する
1)テストメソッドを停止する
describe("Hello World Test") { describe("Normal") { ignore("Set name=Mike") { // ignore() を指定
出力結果
[info] Hello World Test [info] Normal [info] - Set name=Mike !!! IGNORED !!! << ★
2)テストクラスを全体を停止する
import org.scalatest.Ignore @Ignore // ★ここ class HelloWorldTest extends AnyFunSpec with BeforeAndAfterAll {
【3】Public以外のメソッドのテスト
1)private メソッドをテストする
* 「PrivateMethodTester」「PrivateMethod」を使う
https://www.scalatest.org/user_guide/using_PrivateMethodTester
1)サンプル
import org.scalatest.funspec.AnyFunSpec import org.scalatest.PrivateMethodTester class TargetClass { // private method private def sayHi(name: String): String = { require(name.nonEmpty) s"Hi, ${name}!!!" } } class HelloTest extends AnyFunSpec with PrivateMethodTester { describe("For Hello World Test") { val privateMethod = PrivateMethod[String]('sayHi) val targetClass = new TargetClass() it ("For private method test") { assert(targetClass.invokePrivate(privateMethod("Mike")) == "Hi, Mike!!!") } } }
2)protected メソッドをテストする
* UnitTest用にクラスを設けて、そのクラスに継承して そのクラスのメソッドから、親クラスを呼び出すだけ => Scala以外のプログラムのUnitTestでも使える、、、
Hello.scala
class Hello { // ★ protected ★ protected def sayHello(input: String): String = s"${input}, world" }
HelloTest.scala
import org.scalatest.funsuite.AnyFunSuite import org.scalatest.prop.TableDrivenPropertyChecks._ class HelloTest extends AnyFunSuite { // ★注目★ class HelloForUnitTest extends Hello { override def sayHello(input: String): String = { super.sayHello(input) } } test("Your test case") { val target = new HelloForUnitTest val data = Table( ("input", "expected"), ("Hello", "Hello, world"), ("Hi", "Hi, world") ) forAll(data) { (input, expected) => val result = target.sayHello(input) assert(result == expected) } } }
【4】Table で色々なパターンの値を用意する
* Table を使って、テストを行うと可読性があがる => 以下のサンプル参照
1)サンプル
Hello.scala
object Hello { def sayHello(input: String): String = s"${input}, world" }
HelloTest.scala
import org.scalatest.funsuite.AnyFunSuite import org.scalatest.prop.TableDrivenPropertyChecks._ class HelloTest extends AnyFunSuite { test("Your test case") { // ★注目★ val data = Table( ("input", "expected"), ("Hello", "Hello, world"), ("Hi", "Hi, world") ) forAll(data) { (input, expected) => val result = Hello.sayHello(input) assert(result == expected) } } }
【5】例外処理をテストする
* 以下が参考になる
https://www.baeldung.com/scala/scalatest-test-exceptions
エラーを発生させるメソッド
object Hello { def explodingMethod(): Unit = { throw new RuntimeException("Hello, exception!!") } }
1)発生した例外を確認する
package com.example import org.scalatest.funspec.AnyFunSpec class HelloWorldTest extends AnyFunSpec { describe("Abnormal") { it("should produce RuntimeException when name is empty") { // ★注目★ assertThrows[RuntimeException] { Hello.explodingMethod() } } } } }
2)発生した例外+メッセージを確認する
import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers.{a, convertToAnyShouldWrapper} class HelloTest extends AnyFunSuite { test("Hello World Test") { val exception = intercept[Exception](Hello.explodingMethod()) exception shouldBe a[Exception] exception shouldBe a[RuntimeException] exception.getMessage shouldBe "Hello, exception!!" } }
関連記事
Scala ~ テスティングフレームワーク ~
https://dk521123.hatenablog.com/entry/2024/06/07/183708
ScalaTest ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/03/27/001306
ScalaTest ~ 基本編 ~
https://dk521123.hatenablog.com/entry/2023/03/28/003906
ScalaTest ~ with ScalaCheck ~
https://dk521123.hatenablog.com/entry/2023/03/29/000014
ScalaTest ~ with Mockito ~
https://dk521123.hatenablog.com/entry/2023/03/31/002830
ScalaTest ~ with Coverage ~
https://dk521123.hatenablog.com/entry/2023/08/07/222945
specs2 ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2024/06/08/122708
specs2 ~ 基本編 ~
https://dk521123.hatenablog.com/entry/2024/06/09/221005
Scala ~ 環境構築編 ~
https://dk521123.hatenablog.com/entry/2023/03/10/193805
Scala ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/03/12/184331
Scala ~ 基本編 / 繰り返し ~
https://dk521123.hatenablog.com/entry/2023/01/24/000000
Scala ~ 基本編 / Option型 ~
https://dk521123.hatenablog.com/entry/2023/03/09/000000
Scala ~ 基本編 / メソッド ~
https://dk521123.hatenablog.com/entry/2023/03/03/000000
Scala ~ 基本編 / クラス ~
https://dk521123.hatenablog.com/entry/2023/03/14/000857
Scala ~ 基本編 / コレクション ~
https://dk521123.hatenablog.com/entry/2023/03/13/000345
Scala ~ 基本編 / 日付・日時 ~
https://dk521123.hatenablog.com/entry/2023/03/08/000000
Scala ~ 基本編 / 正規表現 ~
https://dk521123.hatenablog.com/entry/2023/03/18/034704
Scala ~ 基本編 / ジェネリック
https://dk521123.hatenablog.com/entry/2023/03/21/003817
Scala ~ Enum ~
https://dk521123.hatenablog.com/entry/2023/01/05/000000
Scala ~ ファイル名・パスの扱い ~
https://dk521123.hatenablog.com/entry/2023/03/11/000000
Scala ~ ファイルハンドリング ~
https://dk521123.hatenablog.com/entry/2023/01/03/000000
Scala ~ YAML ~
https://dk521123.hatenablog.com/entry/2023/03/16/012034
Scala ~ JDBC / DB接続 ~
https://dk521123.hatenablog.com/entry/2023/03/26/000950
Scala ~ AWS SDK ~
https://dk521123.hatenablog.com/entry/2023/03/24/211033
SBT ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/03/22/000000
SBT ~ 基本編 / build.sbt ~
https://dk521123.hatenablog.com/entry/2023/01/27/000000
SBT ~ 基本編 / sbtコマンド ~
https://dk521123.hatenablog.com/entry/2023/01/26/000000
SBT ~ sbtプラグイン ~
https://dk521123.hatenablog.com/entry/2023/01/25/000000
JavaでEmail ~ JavaMail / Text ~
https://dk521123.hatenablog.com/entry/2016/07/16/222422
JavaでEmail ~ JavaMail / 添付ファイル ~
https://dk521123.hatenablog.com/entry/2016/07/17/023459
JavaでEmail ~ SMTP認証 ~
https://dk521123.hatenablog.com/entry/2016/11/07/215251
JavaでEmail ~ SMTP認証 / DIGEST-MD5 ~
https://dk521123.hatenablog.com/entry/2016/12/07/222229
JavaでEmail ~ JavaMail / TLS ~
https://dk521123.hatenablog.com/entry/2017/05/03/163219
JavaでEmail ~ JavaMail / Return-Path・Errors-To ~
https://dk521123.hatenablog.com/entry/2017/05/07/000344
Amazon SES ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2017/04/28/234103
Amazon S3 ~ Boto3編 ~
https://dk521123.hatenablog.com/entry/2019/10/21/230004
Amazon S3 ~ Boto3でファイル存在チェック ~
https://dk521123.hatenablog.com/entry/2022/02/26/182526
AWS Glue ~ Scalaでの実装 ~
https://dk521123.hatenablog.com/entry/2023/03/17/000000
AWS Glue ~ ローカル環境を作成する / Glue v3.0版 ~
https://dk521123.hatenablog.com/entry/2022/01/31/165650
LocalStack ~ ローカルで疑似AWSを作成する ~
https://dk521123.hatenablog.com/entry/2019/12/14/010524
LocalStack ~ ローカルで疑似Lambda/S3/DynamoDBを作成する ~
https://dk521123.hatenablog.com/entry/2019/12/16/231149
SparkからSnowflakeへの接続について考える
https://dk521123.hatenablog.com/entry/2023/03/19/013833
Mockito ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2014/07/18/233904
Mockito ~ 基本編 ~
https://dk521123.hatenablog.com/entry/2014/07/19/121409