2012-01-10 2 views
3

다음 클래스가 있는데 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 
    } 
} 

고마워요!

+1

specs2의 설명서를 볼 수 있습니다. http://etorreborre.github.com/specs2/ –

+0

specs2 문서를 검토했다고 가정합니다. Board 클래스를 감안할 때 메소드를 호출하여 예상대로 코드가 작동하는지 테스트를 작성하여 확인하고 상태 또는 리턴 값을 예상대로 확인하십시오. 몇 가지 예를 보려면 https://github.com/mongodb/casbah/tree/master/casbah-gridfs/src/test/scala 여기를 참조하십시오. http://www.youtube.com/watch?v = lMyNRUuEvNU – foolshat

+0

고마워요, 한 번 봤지만 여전히 이해가 안갑니다! 당신은 내게 보드 클래스에 대한 예제를 주실 수 있습니까? 클래스 BoardSpec이 SpecificationWithJUnit을 확장합니다. – user1137701

답변

-1

코드를 모두 버리는 것이 좋습니다. 어딘가에 저장하고 TDD를 사용하여 0부터 시작하십시오.

Specs2 사이트에는 테스트 작성 방법에 대한 예제가 많이 있지만 TDD - 테스트 기반 디자인을 사용하여 테스트를 수행합니다. 사실을 모른 채 시험을 추가하는 것은 최선책이 아니라고 말합니다.

그래서 가장 단순한 기능을 처리하기를 원하는 가장 간단한 경우를 생각해보십시오. 테스트를 작성하고, 실패했는지 확인하고, 수정하기위한 코드를 작성하십시오. 필요한 경우 리팩터링하고 다음 가장 간단한 경우를 반복합니다.

일반적으로 TDD를하는 방법에 대한 도움이 필요하면 Clean Coders에서 TDD에 대한 동영상을 진심으로지지합니다. 적어도 Bob Martin이 디자인에서 끝까지 전체 클래스 TDD 스타일을 쓰는 두 번째 파트를 지켜보십시오.

일반적으로 테스트하는 방법을 알고 있지만 스칼라 또는 스펙과 관련하여 혼란 스러우면 질문에 대한 내용을 자세히 설명하십시오.

+0

문제는 제가 그 코드를 버릴 수는 없습니다 ... 프로그램이 작동하지만 테스트 용 케이스가 필요합니다. – user1137701

+0

@ user1137701 프로그래머가 될 경우, 코드를 버리고 다시 실행하는 것이 좋습니다. 위의 클래스는 충분히 작아서 모든 내용을 쉽게 다시 작성해야합니다. 그러나, 당신이하고 싶은 일을하십시오. 너가 그것을 원하지 않기 때문에 나는 나의 통보를 바꾸지 않을 것이다. –

4

TDD를 사용하여보다 실용적인 API로 끝나기 때문에 Daniel의 제안은 두 번째입니다.

또한 응용 프로그램이 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가 제안하는 것입니다. 또한 생성 된 데이터를 변경하여 보드가 xo의 교대로 생성되도록해야합니다. 그것은 ScalaCheck 사용법을 배우는 좋은 방법입니다!

+0

안녕하세요, 에릭, 고마워요! 이 코드를 어떻게 시작합니까? JUNIT-Test를 실행하려고했지만 JUNIT 테스트에서 찾을 수없는 결과를 얻었습니다. – user1137701

+0

specs2를 직접 지원하는 Intellij를 사용하고 있습니다. Eclipse를 사용하는 경우 org.specs2.SpecificationWithJUnit을 확장해야합니다 (작동하지 않으면 @RunWith (classOf [JUnitRunner]) 주석을 추가해야합니다 (JUnitRunner가 org.specs2에 있음).runner package)) – Eric

+0

안녕하세요 에릭, 사용하려고했지만 다음 오류가 발생합니다. java.lang.ClassCastException : TestSpec을 org.scalatest.Suite로 캐스팅 할 수 없습니다. – user1137701