Scala spec юнит-тесты - PullRequest
       19

Scala spec юнит-тесты

3 голосов
/ 10 января 2012

У меня есть следующий класс, и я хочу написать несколько тестов для Spec, но я действительно новичок в этом и не знаю, как начать.Мой класс действительно выглядит так:

class Board{

  val array = Array.fill(7)(Array.fill(6)(None:Option[Coin]))

  def move(x:Int, coin:Coin) {
    val y = array(x).indexOf(None)
    require(y >= 0) 
    array(x)(y) = Some(coin)
   }

  def apply(x: Int, y: Int):Option[Coin] = 
     if (0 <= x && x < 7 && 0 <= y && y < 6) array(x)(y)
     else None

  def winner: Option[Coin] = winner(Cross).orElse(winner(Naught))

  private def winner(coin:Coin):Option[Coin] = {
    val rows = (0 until 6).map(y => (0 until 7).map( x => apply(x,y)))
    val cols = (0 until 7).map(x => (0 until 6).map( y => apply(x,y)))
    val dia1 = (0 until 4).map(x => (0 until 6).map( y => apply(x+y,y)))
    val dia2 = (3 until 7).map(x => (0 until 6).map( y => apply(x-y,y)))

    val slice = List.fill(4)(Some(coin))
    if((rows ++ cols ++ dia1 ++ dia2).exists(_.containsSlice(slice))) 
      Some(coin)
    else None
  }  

  override def toString = {
    val string = new StringBuilder
    for(y <- 5 to 0 by -1; x <- 0 to 6){
        string.append(apply(x, y).getOrElse("_"))
        if (x == 6) string.append ("\n") 
        else string.append("|")
    }
    string.append("0 1 2 3 4 5 6\n").toString
  }
}

Спасибо!

Ответы [ 2 ]

4 голосов
/ 11 января 2012

Я могу только поддержать предложение Даниэля, потому что вы получите более практичный API с использованием TDD.

Я также думаю, что ваше приложение может быть хорошо протестировано с сочетанием specs2 и ScalaCheck .Вот черновик спецификации, с которой можно начать:

  import org.specs2._
  import org.scalacheck.{Arbitrary, Gen}

  class TestSpec extends Specification with ScalaCheck { def is =

    "moving a coin in a column moves the coin to the nearest empty slot" ! e1^
    "a coin wins if"                                                     ^
      "a row contains 4 consecutive coins"                               ! e2^
      "a column contains 4 consecutive coins"                            ! e3^
      "a diagonal contains 4 consecutive coins"                          ! e4^
                                                                         end

    def e1 = check { (b: Board, x: Int, c: Coin) =>
      try { b.move(x, c) } catch { case e => () }
      // either there was a coin before somewhere in that column
      // or there is now after the move
      (0 until 6).exists(y => b(x, y).isDefined)
    }

    def e2 = pending
    def e3 = pending
    def e4 = pending

    /**
     * Random data for Coins, x position and Board
     */
    implicit def arbitraryCoin: Arbitrary[Coin]     = Arbitrary { Gen.oneOf(Cross,       Naught) }
    implicit def arbitraryXPosition: Arbitrary[Int] = Arbitrary { Gen.choose(0, 6) }
    implicit def arbitraryBoardMove: Arbitrary[(Int, Coin)]   = Arbitrary {
      for {
        coin <- arbitraryCoin.arbitrary
        x    <- arbitraryXPosition.arbitrary
      } yield (x, coin)
    }
    implicit def arbitraryBoard: Arbitrary[Board]   = Arbitrary {
      for {
        moves <- Gen.listOf1(arbitraryBoardMove.arbitrary)
      } yield {
        val board = new Board
        moves.foreach { case (x, coin) => 
          try { board.move(x, coin) } catch { case e => () }}
          board
      }
    }


  }

  object Cross extends Coin {
    override def toString = "x"
  }
  object Naught extends Coin {
    override def toString = "o"
  }
  sealed trait Coin

Свойство e1, которое я реализовал, нереально, потому что оно не проверяет, действительно ли мы переместили монету в ближайший пустой слот, который предлагает ваш код и ваш API.Вы также захотите изменить сгенерированные данные так, чтобы платы создавались с чередованием x и o.Это должен быть отличный способ научиться использовать ScalaCheck!

0 голосов
/ 10 января 2012

Я предлагаю вам выбросить весь этот код - хорошо, сохраните его где-нибудь, но начните с нуля, используя TDD.

На сайте Specs2 есть множество примеров написания тестов, но для этого используется TDD - дизайн, управляемый тестами. Добавление тестов по факту является неоптимальным, если не сказать больше.

Итак, подумайте о самом простом случае, который вы хотите обработать, о самой простой функции, напишите тест для этого, увидите, что он не работает, напишите код, чтобы исправить это. При необходимости выполните рефакторинг и повторите для следующего самого простого случая.

Если вам нужна помощь в работе с TDD в целом, я от всей души одобряю видеоролики о TDD, доступные на Clean Coders . По крайней мере, посмотрите вторую часть, где Боб Мартин пишет весь класс в стиле TDD, от дизайна до конца.

Если вы знаете, как проводить тестирование в целом, но не знаете, что такое Scala или Spec, пожалуйста, уточните, какие у вас вопросы.

...