web-dev-qa-db-ja.com

Scalaでプライベートクラスメソッドをテストするにはどうすればよいですか?

次のようなプライベートメソッドを持つコンパニオンオブジェクトがあります。

package com.example.people

class Person(val age: Int)

object Person {
  private def transform(p: Person): Person = new Person(p.age + 1)
}

次のようなもので、このメソッドをテストしたいと思います。

class PersonSpec extends FlatSpec {

  "A Person" should "transform correctly" in {
    val p1 = new Person(1)
    val p2 = Person.transform(p1) // doesn't compile, because transform is private!
    assert( p2 === new Person(2) )
  }

}

テストコードがプライベートメソッドにアクセスするのに役立ちますか?

実際、書かれているとおり、Personのサブクラスを作成できるかもしれませんが、Personfinalまたはsealedとして宣言されている場合はどうでしょうか。

ありがとう!

34
gdiazc

すべてをテストすることになると、私は真ん中にいます。私は通常すべてをテストするわけではありませんが、それを可能にするためにコードをマングルしなくてもプライベート関数を単体テストできると便利な場合があります。 ScalaTestを使用している場合は、PrivateMethodTesterを使用して実行できます。

import org.scalatest.{ FlatSpec, PrivateMethodTester }

class PersonSpec extends FlatSpec with PrivateMethodTester {

  "A Person" should "transform correctly" in {
      val p1 = new Person(1)
      val transform = PrivateMethod[Person]('transform)
      assert(p2 === invokePrivate transform(p1))
    }
  }

それはあなたがしたいことではないかもしれませんが、あなたはアイデアを得ます。

57
jlegler

メソッドをパッケージプライベートとして宣言できます。

private[people] def transform(p: Person): Person = new Person(p.age + 1)

PersonSpecを同じパッケージに入れると、それにアクセスできるようになります。

プライベートメソッドを単体テストすることが本当に賢明かどうかを判断するのはあなたにお任せします:)

29
vptheron

プライベートメソッドを単体テストする必要があるのは、デザインの匂いです。

パブリックAPIを使用してテストします。パブリックAPIは、小さくてヘルパーメソッドである場合は問題ありません。または、可能性が高く、異なるロジック/責任が含まれており、Personの委任で使用される別のクラスに移動する必要があります。次に、そのクラスのパブリックAPIを最初にテストします。

詳細については、 関連する回答 を参照してください。

Java/Scalaリフレクションを使用してアクセスできる可能性がありますが、設計上の問題の回避策にすぎません。それでも、必要な場合は、 related Javaその方法の答え を参照してください。

8
Peter Kofler

ユニットテストはクラスのコントラクトをテストすることではないと思います-それは単純な機能(ユニット)をテストすることです。

また、簡単にテストできるようにするためだけに、いくつかのメソッドを公開するのは良い考えだとは思いません。 APIをできるだけ狭く保つことは、他の開発者がコードを使用して(IDEがプライベートメソッドを提案しない)、契約を理解するのに役立つ良い方法だと思います。

また、すべてを単一のメソッドに入れるべきではありません。そのため、プライベートメソッドにいくつかのロジックを入れることができる場合があります。もちろん、テストすることもできます。パブリックAPIを介してテストすると、テストの複雑さが増します(他のオプションは、プライベートメソッドのロジックを別のヘルパークラスに移動し、そこでテストすることです。このクラスは、開発者が直接使用することはなく、APIを混乱させません)

Scalatestの人は、目的のためにPrivateMethodTesterを追加したと思います。

1
Deil

個人的には、すべてを公開し、_または__は、他の開発者が使用すべきでないことを示します。

私はこれがScalaであり、Pythonではないが、それにもかかわらず、 "ここで私たちはすべて大人に同意しています。"

「プライベート」メソッドは、実際にはプライベートではなく( 、たとえば )、確かに安全ではないので、本質的に社会契約であるものの生活を難しくする理由?他の開発者が暗い場所でぶらぶらしたい場合、彼らは正当な理由があるか、彼らが得るものに値するかのいずれかです。

1
MikeTwo

ここでの@jleglerの答えは私を助けましたが、物事が機能する前にまだデバッグが必要だったので、ここでこれに必要なものを正確に書きたいと思いました。

テストする:

class A

object A {
  private def foo(c: C): B = {...}
}

使用する:

val theFuncion = PrivateMethod[B]('foo)
val result = A invokePrivate theFunction(c)

A、Bの位置に注意してください

1
Dotan

一般的に言って、コードを効果的にテストしたい場合、firstをテスト可能に記述する必要があります。

Scalaは機能的なパラダイムを実装し、設計によって不変オブジェクトを広範囲に使用します。「ケースクラス」は例です(私の意見:Personクラスはケースクラスでなければなりません)。

オブジェクトに可変状態がある場合、プライベートメソッドの実装は意味があります。この場合、オブジェクトの状態を保護することができます。しかし、オブジェクトが不変の場合、なぜメソッドをプライベートとして実装するのですか?あなたの例では、メソッドはPersonのコピーを作成しますが、どのような理由でプライベートにしたいのですか?理由はわかりません。

これについて考えることをお勧めします。繰り返しますが、コードを効果的にテストするには、テスト可能なコードを作成する必要があります。

1
Marco

可能な回避策は、プライベートメソッドを間接的にテストすることです。プライベートメソッドを呼び出すパブリックメソッドをテストします。

0
Septem