Specs2 and Scalacheck - mixing ForEach context with properties - scala

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

Related

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...

Scala Implicit Type Conversion of Classes with Type Parameters

I'm trying to add functionality to the scala.collection.Iterable trait, more specifically, a printerate function that iterates through the elements and prints them out (to the console if there are no parameters, otherwise to the outputstream param). I'm using a predefined extension method that I created for object, printSelf(). However, this is causing an compiler error, 'Value printSelf is not a member of type parameter Object.' I'd also like to have this an a separate file so that it's easy for me to use between several projects and applications.
Here's my current code for my conversion file:
import java.io.OutputStream
import scala.collection.Iterable
package conversion{
class Convert {
implicit def object2SuperObject(o:Object) = new ConvertObject(o)
implicit def iterable2SuperIterable[Object](i:Iterable[Object]) = new ConvertIterable[Object](i)
}
class ConvertObject(o:Object){
def printSelf(){
println(o.toString())
}
def printSelf(os:OutputStream){
os.write(o.toString().getBytes())
}
}
class ConvertIterable[Object](i:Iterable[Object]){
def printerate(){
i.foreach {x => x.printSelf() }
}
def printerate(os:OutputStream){
i.foreach { x => x.printSelf(os) }
}
}
}
I'm also getting a similar error in the code that's trying to test this out, 'value printerate is not a member of scala.collection.immutable.Range':
import conversion.Convert
package test {
object program extends App {
new testObj(10) test
}
class testObj(i: Integer) {
def test(){
val range = 0.until(i)
0.until(i).printerate()
}
}
}
What's wrong with the way that I'm approaching this type conversion?
Several things in fact:
Convert should be an object, not a class.
You use Object instead of Any
You use Object as a generic type identifier, instead of the much less confusing T.
You do not import the implicit definitions (it's not enough to import the object itself).
This should work:
package conversion {
object Convert {
implicit def object2SuperObject(o: Any) = new ConvertObject(o)
implicit def iterable2SuperIterable[T](i:Iterable[T]) = new ConvertIterable[T](i)
}
class ConvertObject(o: Any){
def printSelf(){
println(o.toString())
}
def printSelf(os:OutputStream){
os.write(o.toString().getBytes())
}
}
class ConvertIterable[T](i:Iterable[T]){
import Convert.object2SuperObject
def printerate(){
i.foreach {x => x.printSelf() }
}
def printerate(os:OutputStream){
i.foreach { x => x.printSelf(os) }
}
}
}
import conversion.Convert._
Second file:
package test {
object program extends App {
new testObj(10) test
}
class testObj(i: Integer) {
def test(){
val range = 0.until(i)
0.until(i).printerate()
}
}
}

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 { ??? }
}

Simple test with Scala Test 1.2

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