Vamos a hacer algunos test con ScalaTest. Empecemos haciendo una clase:
case class Guest(name: String)
case class Room(number: Int, guest: Option[Guest] = None){ room =>
def isAvailable(): Boolean = ???
def checkin(guest: Guest): Room = ???
def checkout(): Room = ???
}
/*
* We will automatically create 10 rooms
* if these are not specified.
*/
case class Hotel(
rooms: List[Room] = (1 to 10).map(n => Room(number=n)).toList){
def checkin(personName: String): Hotel = ???
}
Hemos hecho una clase Hotel que contiene 10 habitaciones. El ??? significa que el metodo no fue definido, pero me permite compilar. Vamos a trabajar bien TDD.
Antes que nada agregamos el framework al proyecto utilizando sbt:
libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.4" % "test"
Ahora vamos a hacer una clase común para reutilizar métodos comunes:
package org.me.hotel
import org.scalatest.{FlatSpec,Matchers}
abstract class UnitTest(component: String) extends FlatSpec
with Matchers{
behavior of component
}
Como se puede ver hicimos una clase padre o general para todos los tests, esta extiende de FlatSpec e implementa Matchers.
A la vez le pasamos por parámetro el nombre del componente a probar. Si quisieramos utilizar esta clase lo hariamos de la siguiente manera:
class MyClassUnitTest extends UnitTest("MyClass")
A la vez utilizamos Matchers dado que nos provee expresiones más cercanas a los humanos como:
(2+2) should equal (4)
(2+2) shouldEqual 5
(2+2) should === (4)
(2+2) should be (4)
(2+2) shouldBe 5
Bueno ahora definimos nuestro test:
package org.me.hotel
class RoomTest extends UnitTest("Room") {
it should "provide info about its occupation" in {
Room(1).isFree() shouldEqual true
Room(1,None).isFree() shouldEqual true
Room(1,Some(Guest("Bruce"))).isFree() shouldEqual false
}
it should "allow registering a new guest if room is free" in {
val occupiedRoom = Room(1).checkin(Guest("James"))
occupiedRoom.isFree shouldEqual false
occupiedRoom.guest shouldEqual(Option(Guest("James")))
}
it should "deny registering a new guest if room is already occupied" in {
an [IllegalArgumentException] should be thrownBy {
Room(1,Some(Guest("Barbara"))).checkin(Guest("Bruce"))
}
}
it should "deny checking out if room is already free" in {
an [IllegalArgumentException] should be thrownBy {
Room(1).checkout()
}
}
it should "allow checking out if room is occupied by someone" in {
val room = Room(1,Some(Guest("Carmine")))
val freeRoom = room.checkout()
freeRoom.isFree shouldEqual true
}
}
Como se puede ver los test quedan escritos casi en lenguaje natural.
Si corremos los tests nos darán un error:
> test
[info] RoomTest:
[info] Room
[info] - should provide info about its occupation *** FAILED ***
[info] scala.NotImplementedError: an implementation is missing
[info] at scala.Predef$.$qmark$qmark$qmark(Predef.scala:252)
[info] at org.me.hotel.Room.isFree(Room.scala:6)
[info] at org.me.hotel.RoomTest$$anonfun$1.apply$mcV$sp(RoomTest.scala:6)
[info] at org.me.hotel.RoomTest$$anonfun$1.apply(RoomTest.scala:5)
...
[info] Run completed in 699 milliseconds.
[info] Total number of tests run: 15
[info] Suites: completed 6, aborted 0
[info] Tests: succeeded 3, failed 12, canceled 0, ignored 0, pending 0
[info] *** 12 TESTS FAILED ***
[error] Failed tests:
[error] org.me.hotel.RoomTest
[error] org.me.hotel.HotelTest
[error] (test:test) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 6 s, completed 12-ago-2015 16:08:47
Ahora a hacer que nuestras clases pasen sus tests, Suerte!!!!