Simple test with Scala Test 1.2 - scala

I'm trying to run a test using Scala 2.8 in IntelliJ 10 with Scala Test 1.2
I don't know much scala syntax, so can you help with this code ? :)
package test.ui {
import org.scalatest._
import matchers.ShouldMatchers
import ui._
import observer._
object ButtonObserverSpecification extends Spec {
"A Button Observer should observe button clicks" in {
val observableButton = new ObservableButton("Okay")
val buttonObserver = new ButtonCountObserver
observableButton.addObserver(buttonObserver)
for (i <- 1 to 3) observableButton.click()
buttonObserver.count should equal (3)
}
}
}
The error is :
error: value in is not a member of java.lang.String
"A Button Observer should observe button clicks" in {
Here is the rest of the code :
package ui {
abstract class Widget
class Button(val label: String) extends Widget {
def click() = {
println (label + " was clicked")
}
}
}
package observer {
trait Subject {
type Observer = {def receiveUpdate(subject: Any)}
private var observers = List[Observer]()
def addObserver(observer: Observer) = observers ::= observer
def notifyObservers = observers foreach (_.receiveUpdate(this))
}
}
package ui {
import observer._
class ObservableButton(name: String) extends Button(name) with Subject {
override def click() = {
super.click()
notifyObservers
}
}
class ButtonCountObserver {
var count = 0
def receiveUpdate(subject: Any) = count += 1
}
}
The code is from the book "Programming Scala" from Oreilly
I tried updating the code to Scala test 1.2, but failed. Here is the original test (notice the imports and the extended class):
package ui
import org.specs._
import observer._
object ButtonObserverSpec extends Specification {
"A Button Observer" should {
"observe button clicks" in {
val observableButton = new ObservableButton("Okay")
val buttonObserver = new ButtonCountObserver
observableButton.addObserver(buttonObserver)
for (i <- 1 to 3) observableButton.click()
buttonObserver.count mustEqual 3
}
}
}
Trial number 3 (Error is No tests were found) :
package test.ui {
import org.scalatest._
import matchers.ShouldMatchers
import ui._
import observer._
import org.scalatest.junit.JUnitRunner
import org.junit.runner.RunWith
#RunWith(classOf[JUnitRunner])
object ButtonObserverTest extends WordSpec with ShouldMatchers {
"A Button Observer" should {
"observe button clicks" in {
val observableButton = new ObservableButton("Okay")
val buttonObserver = new ButtonCountObserver
observableButton.addObserver(buttonObserver)
for (i <- 1 to 3) observableButton.click()
buttonObserver.count should equal (3)
}
}
}
}
Working test :
package test.ui {
import org.scalatest.WordSpec
import org.scalatest.matchers.ShouldMatchers
import ui._
import observer._
class ButtonObserverTest extends WordSpec with ShouldMatchers {
"A Button Observer" should {
"observe button clicks" in {
val observableButton = new ObservableButton("Okay")
val buttonObserver = new ButtonCountObserver
observableButton.addObserver(buttonObserver)
for (i <- 1 to 3) observableButton.click()
buttonObserver.count should equal (3)
}
}
}
}
PS : If you don't know how to run scala tests in IntelliJ, see this blog post - IntelliJ Now Supports ScalaTest

I think you need to extend WordSpec with ShouldMatchers like this :
class ButtonObserverSpec extends WordSpec with ShouldMatchers {...}
You can find more examples here:
http://www.scalatest.org/getting_started_with_bdd

Related

Specs2 and Scalacheck - mixing ForEach context with properties

I'm writing Specs2 tests that use a temporary file and properties from ScalaCheck. Without properties it works fine :
import better.files.File
import org.specs2.execute.{AsResult, Result}
import org.specs2.mutable.Specification
import org.specs2.specification.ForEach
trait TmpDirContext extends ForEach[File] {
def foreach[R: AsResult](testWithFile: File => R): Result = {
val tmpDirCtx = File.temporaryDirectory()
AsResult(tmpDirCtx.apply(testWithFile))
}
}
class OkTest extends Specification with TmpDirContext {
import better.files._
"Example" should {
"work" in { tmpDir: File =>
tmpDir.exists must beTrue
}
}
}
val test = new OkTest
specs2.run(test)
If I add properties, it doesn't compile :
import org.scalacheck.Prop
import org.specs2.ScalaCheck
class KoTest extends Specification with ScalaCheck with TmpDirContext {
"KoTest" should {
"work" in { tmpDir: File =>
"for" ! Prop.forAll { value: Int =>
tmpDir.exists must beTrue
}
}
}
Error:(26, 16) could not find implicit value for evidence parameter of type org.specs2.execute.AsResult[better.files.File => org.specs2.specification.core.Fragment]
"work" in { tmpDir: File =>
I've managed to make it compile, but then the test fails seemingly because the ForEach from TmpDirContext has already disposed of a temporary folder:
class KoTest2 extends Specification with ScalaCheck with TmpDirContext {
"KoTest2" should {
"work" >> { tmpDir: File =>
Prop.forAll { value: Int =>
tmpDir.exists must beTrue
}
}
}
}
I guess I'm missing something... How to make it work and have the tmpDir available in the property testing?
You can try the following approach
import org.specs2.mutable.Specification
import java.io.File
import org.specs2.ScalaCheck
import org.scalacheck._
class KoTest extends Specification with ScalaCheck with TempDir { sequential
"KoTest" should {
"work" >> {
"for" >> prop { (tmpDir: File, value: Int) =>
tmpDir.exists must beTrue
}.after(deleteTmpDir)
}
}
}
trait TempDir {
implicit def arbitraryTempDir: Arbitrary[File] =
Arbitrary(tmpDir)
val tmpDir = new File("temp")
def deleteTmpDir = tmpDir.delete
}
It is presented here

How to test a custom directive / extract value from akka.http.scaladsl.server.Directive?

I have a custom directive with a function like the following that returns a Directive1[ValidatedParameters], where ValidatedParameters is just a simple case class:
class MyCustomDirective {
def validateParameters(...): Directive1[ValidatedParameters] = {
...
provide(ValidatedParameters(...))
}
}
I'm using it like this in my route:
myCustomDirective.validateParameters(top, skip, modifiedDate) {
(validatedParameters: ValidatedParameters) => {
However, I have a unit test where I'd basically like to call the above function and verify that ValidatedParameters is what I expect:
val actualResult: Directive1[ValidatedParameters] = new MyCustomDirective().validateParameters(...)
So actualResult is a Directive1[ValidatedParameters], is there a way I can get access to the ValidatedParameters case class within this directive from a unit test?
Here is a solution for writing a test case for the custom directive as mentioned here:
REQUEST ~> ROUTE ~> check {
ASSERTIONS
}
For a custom directive to get page and per_page query paramters:
case class Paginate(page: Option[String], perPage: Option[String])
trait PaginationDirective extends ParameterDirectives with RespondWithDirectives {
def withPagination: Directive1[Paginate] = {
parameters(
(
"page".as[String].?,
"per_page".as[String].?
)
).tmap { case (pageOpt, perPageOpt) => Paginate(pageOpt, perPageOpt) }
}
def logCurrentPage(currentPage: Int): Directive0 = {
mapResponse(response => {
logger.info(s"currentPage is $currentPage")
response
})
}
}
Test case for the above custom directive:
import akka.http.scaladsl.server.Directives.complete
import akka.http.scaladsl.testkit.ScalatestRouteTest
import org.scalatest.{Matchers, WordSpec}
class PaginationDirectiveTest extends WordSpec with Matchers with PaginationDirective with ScalatestRouteTest {
"paginate directive" should {
"return page and per page parameters" in {
Get("/?page=1&per_page=25") ~> withPagination(i => complete(i.toString)) ~> check {
responseAs[String] shouldEqual "[Paginate(Some(1), Some(25))]"
}
}
"logCurrentPage" should {
Get("/hello") ~> logCurrentPage(5)(complete("Dummy msg")) ~> check {
//validate test here.
}
}
}
I ended up with the following:
import akka.http.scaladsl.server.Directives.complete
import akka.http.scaladsl.testkit.ScalatestRouteTest
import de.heikoseeberger.akkahttpcirce.ErrorAccumulatingCirceSupport._
import org.scalamock.scalatest.MockFactory
import org.scalatest.{BeforeAndAfter, Matchers}
class MyTest extends ScalatestRouteTest {
...
"validate(top=None, skip=None, modifiedDate=None)" should "pass validation" in {
myCustomDirective.validate(top, skip, modifiedDate) {
(validatedParameters: ValidatedParameters) => {
validatedParameters shouldEqual expectedResult
complete("") // Needed to pass compilation
}
}
}
}

Reuse mock declaration across tests

I'd like to reuse mock declarations accross tests (if possible).
Here is a minimal non-working example using ScalaTest and Mockito. I'm expecting the ​yes​ value in the first test but I get the ​other​ value.
It seems that the latest Mockito.when is the one applied for all test clauses.
Is there a way to avoid declaring mocks in each in clause?
import org.mockito.Mockito._
import org.scalatest.mock.MockitoSugar
import org.scalatest.{Matchers, WordSpec}
​
class ReuseMocksSpec extends WordSpec with Matchers with MockitoSugar {
"A test" when {
val service = mock[Service]
"sharing mocks among tests" should {
when(service.getVal).thenReturn("yes")
"get yes value" in {
service.getVal should be("yes")
}
}
"sharing mocks among other tests" should {
when(service.getVal).thenReturn("other")
"get other value" in {
service.getVal should be("other")
}
}
}
​
trait Service {
def getVal: String
}
}
I reviewed the way I designed it and am now using a function to build my mocks:
def withValue(value: String)(body: (Service => String)) = {
val service = mock[Service]
when(service.getVal).thenReturn(value)
body(service)
}
The test class would become:
import org.mockito.Mockito._
import org.scalatest.mock.MockitoSugar
import org.scalatest.{Matchers, WordSpec}
class ReuseMocksSpec extends WordSpec with Matchers with MockitoSugar {
"A test" when {
"sharing mocks among tests" should {
"get yes value" in {
val value = withValue("yes") { service =>
service.getVal
}
value should be("yes")
}
}
"sharing mocks among other tests" should {
"get other value" in {
val value = withValue("other") { service =>
service.getVal
}
value should be("other")
}
}
}
def withValue(value: String)(body: (Service => String)) = {
val service = mock[Service]
when(service.getVal).thenReturn(value)
body(service)
}
trait Service {
def getVal: String
}
}
I don't know if it's the cleanest and easiest way to do it but it works...

Specs2 with Scaldi - wrong implicit injector being invoked

I'm trying to run a test with scaldi and specs2. In the test I need to override a StringManipulator function that uses an injected ProxyManipulator. The ProxyManipulator takes a string and returns its upper case in a Future. The replacement manipulator in the test returns a Future("Test Message").
Here is the StringManipulator class where the injection occurs:
class StringManipulator {
def manip (str : String) (implicit inj: Injector) : String = {
val prox = inject[ProxyManipulator]
Await.result(prox.manipulate(str), 1 second)
}
}
I'm using a package.object that contains the implicit injector:
import modules.MyModule
package object controllers {
implicit val appModule = new MyModule
}
And here is the specs2 test with the new binding:
#RunWith(classOf[JUnitRunner])
class StringManipScaldiSpec extends Specification {
class TestModule extends Module {
bind [ProxyManipulator] to new ProxyManipulator {
override def manipulate(name: String) = Future("Test Message")
}
}
"Application" should {
"do something" in {
val myTestModule = new TestModule
val str = "my string"
val stringMan = new StringManipulator() //(myTestModule)
stringMan.manip(str)(myTestModule) === "Test Message"
}
}
}
The problem is that when the test runs the class StringManipulator is still using the original Proxy Manipulator instead of the one passed in the TestModule. Any ideas?

How to set vals to be used in tests?

I've been noticing a lot of repetition to set up each test with Play/specs2. I'm aware that you can create a trait that extends mutable.Before and use that to set up tests but any values created there seem to be out of scope for my tests.
What I would like to be able to do is set val user = User.create("User Name") in a class or trait before each test runs so I can have access to user later on in the test. How can this be achieved?
// SpecificationWithFixtures.scala
package models
import org.specs2.execute.{AsResult, Result}
import org.specs2.mutable._
import play.api.test.Helpers._
import play.api.test._
abstract class SpecificationWithFixtures extends Specification {
abstract class WithFakeDB extends WithApplication(FakeApplication(additionalConfiguration = inMemoryDatabase())) {
override def around[T: AsResult](t: => T): Result = super.around {
t
}
}
}
// UserSpec.scala
package models
import org.junit.runner._
import org.specs2.runner._
#RunWith(classOf[JUnitRunner])
class UserSpec extends SpecificationWithFixtures {
"User.create" should {
"save user in the database" in new WithFakeDB {
val user = User.create("User Name")
// Some test for user
}
}
"User.findAll" should {
"return a list of all users" in new WithFakeDB {
val user = User.create("User Name")
// Another test for user
}
}
}
What you can do is something like:
def withUser[T](test: User => T): T = test(User create "Username")
// or even more configurable
def withUser[T](name: String)(test: User => T): T = test(User create name)
// Then writing expectations you can do
"User Roger" in withUser("Roger") {
roger => // trivial example
roger.name must_== "Roger"
}
// or even
"User" in withUser("John") {
_.name must_== "John"
}
This kind of loan pattern is useful writing specs2.
In previous example it's user per expectation (in), but it can be used for a group of expectations (should, >>), or for all.
"User" should withUser("xyz") {
"exp1" in { ??? }
}