3

次の順番を強く区別するゲームのタイプ階層を考えると、次のようになります。

trait Game
trait BlackToPlay extends Game {
  def move(p: BlackPiece, s: Square): Either[FinishedGame, WhiteToPlay]
}
trait WhiteToPlay extends Game {
  def move(p: WhitePiece, s: Square): Either[FinishedGame, BlackToPlay]
}

反省に頼ることなく、次の重要な主張をすることはできますか?

"A game with white to play" should {
  "not allow black to play" in {
    // an instance of whiteToPlay should not 
    // have the `move(BlackPiece, Square)` method.
  }
}

編集:@Martinのソリューションを実装しようとしてもうまくいきません。ここで何が悪いのかについて何か考えはありますか?REPLから:

scala> class B() {
     |   def b(s: String) = s
     | }
defined class B

scala> val b = new B()
b: B = B@420e44

scala> b.c("")
<console>:8: error: value c is not a member of B
       b.c("")
         ^

scala> b match {
     |   case _: { def c(s: String) } => false
     |   case _ => true
     | }
warning: there were unchecked warnings; re-run with -unchecked for details
res7: Boolean = false

res7bの構造タイプと一致してはならないため、真である必要があります{ def c(s: String) }

4

6 に答える 6

5

型システムがすでに保証しているものをテストしません。実際、型システムはすでにプログラムの特定のプロパティのテストです。

さらに、所有しているタイプが特定のプロパティを保証していることをテストすることもできます(たとえば、2回続けて移動するプレーヤーがいないなど)が、現時点では、この種のことはAgdaやCoqなどの言語に制限されています。

于 2011-03-12T14:52:36.220 に答える
3

BlackPieceがWhitePieceのサブタイプではないと仮定します。

WhiteToPlayInstance.move(BlackPiece、s)はコンパイルしないでください。つまり、テストを作成することはできません。型システムは、WhiteToPlayでBlackPieceを移動できないことを保証します。

于 2011-03-12T06:43:22.393 に答える
1

編集: Thomasが指摘したように、構造型はJVMバージョンのscalaのパターン一致では使用できないため、以下の答えは意味がありません。


通常の状況では、scalaは静的に型付けされ、そのようなものはコンパイラーによって処理されるため、これはあまり意味がありませんが、コードでリフレクションまたは構造型型付けを大量に使用する場合は、良いテストになる可能性があります。

instance match {
  case x: { def move(p: BlackPiece, s: Square): Either[FinishedGame, WhiteToPlay] } => // error
  case _ => // no error
}
于 2011-03-12T07:30:47.050 に答える
1

本当にそのようなことをテストしたい場合は、チェックをタイプチェックから動的なものに移動してください。それを仮定し、共通のスーパータイプを共有しWhitePieceます:BlackPiecePiece

trait Game {
  def move(p : Piece, s : Square) : Either[FinishedGame, WhiteToPlay]
}

trait BlackToPlay extends Game
trait WhiteToPlay extends Game

次に、テストは次のようになります。

val b2p : BlackToPlay = ...
val bp : BlackPiece = ...
val wp : WhitePiece = ...
{a move bp} must not produce [IllegalMoveException]
{a move wp} must produce [IllegalMoveException]

これが適切な設計になるかどうかはわかりませんが、システムを明示的にテスト可能にします。

于 2011-03-13T20:01:06.660 に答える
1

リフレクションソリューションが必要ないことはわかっていますが、(scala 2.9が受け入れられる場合は)次のような新しい動的トレイトを使用できます。

class ReflectionDynamic[T <: AnyRef](t: T) extends Dynamic {
  def typed[A]: A = sys.error("doh");

  def applyDynamic(name: String)(args: Any*) = {
    val argRefs = args.map {
      case a: AnyRef => a
      case _ => sys.error("only AnyRefs")
    }
    t.getClass.getMethod(name, argRefs.map(_.getClass): _*).invoke(t, argRefs: _*)
  }
}

...そしてそれはこの肯定的なテストを与えるでしょう:

val dynamicWhiteToPlay = new ReflectionDynamic(whiteToPlay)
dynamicWhiteToPlay.move(new WhitePiece, new Square) must_== Right(blackToPlay)

...そしてこれはネガティブです:

dynamicWhiteToPlay.move(new BlackPiece, new Square) must throwA[NoSuchMethodException]
于 2011-03-15T00:35:47.270 に答える
1

質問は質問に似ています。与えられた場合、コンパイラによって拒否されたものval f: (Boolean) => Intをテストするにはどうすればよいですか?f("hello world")

メルボルンのScalaユーザーグループでの簡単な会話の後、私の質問は検証されました(イェーイ)。結局のところ、私がテストしようとしている制限は設計に含まれているため、テストに値します。

Bernie Popeは、必要なメカニズムは自動定理証明であると提案しました。@ daniel-c-sobralは親切にも、わずかに異なるコンテキストでAgdaとCoqに言及しました。実際、これらは私のアプリケーションが正しいことを証明できるATPテクノロジーです。

もう1つの提案は、問題のあるコードをスクリプトとして実行し、失敗したことを表明することでした。evalあなたが好きなら、貧乏人。

于 2011-03-28T23:24:06.170 に答える