How to do unit testing in Scala - scala

I am trying to learn scala (and also the concept of unit testing).
I have an object
object Foo{
def parse(s:String): Array[String] = {
return s.split(",")
}
}
A very simple code block.. but now I want to write unit test?
My code structure is:
src/main/scala/foo.scala
src/test/scala/(empty)
I am using sbt to compile and run?
Thanks

put this in src/test/scala/FooSpec.scala
import org.specs2.mutable.Specification
class FooSpec extends Specification {
"Foo" should {
"parse a String" in {
Foo.parse("a,b") == Array("a","b")
}
}
}
then in the sbt prompt you can run test
for this to work you will need to add a dependency on specs 2 in your build.sbt as explained in the documentation
libraryDependencies ++= Seq(
"org.specs2" %% "specs2" % "2.3.11" % "test"
)

It's a very big topic.
I'm a proponent of Specs2 along with its Mockito and ScalaCheck support. All of these have good documentation, so I recommend you start by looking them up on the Web.

Related

Is it possible to parse Json in build.sbt?

I want to validate a downloaded Json file from server during build time and failed the build, if there are any errors.
Is it possible to parse/validate Json in build.sbt?
Your build.sbt is scala code so it can do everything you can do with other scala code.
You should be able to add dependencies (e.g. a json parsing library) of your build.sbt code in project/build.sbt since sbt is recursive.
Here is an example to supplement Jasper-M's answer.
For example, add liahoy's requests-scala HTTP client library, and upickle JSON deserialisation library to project/builds.sbt
libraryDependencies ++= List(
"com.lihaoyi" %% "requests" % "0.6.0",
"com.lihaoyi" %% "upickle" % "1.1.0"
)
Then under project/Preconditions.scala add the following object which will contain assertions you want to check before running the build
object Preconditions {
import scala.util.Try
import requests._
import upickle.default._
case class User(login: String, id: Int)
implicit val userRW: ReadWriter[User] = macroRW
def validateUserJson() = {
val result = Try(read[User](get("https://api.github.com/users/lihaoyi").text)).isSuccess
assert(result, "User JSON should be valid")
}
}
Now these facilities will be available to build.sbt under the root project. Lets create a task in build.sbt to run the assertions
lazy val checkPreconditions = taskKey[Unit]("Validate pre-conditions before building")
checkPreconditions := {
Preconditions.validateUserJson()
println("All preconditions passed!")
}
and finally lets make compile task dependant on checkPreconditions task using dependsOn like so
Compile / compile := (Compile / compile).dependsOn(checkPreconditions).value
Now executing sbt compile should check pre-conditions before proceeding with compilation.

How to get the package of methods or objects in Scala?

How to get the package of methods or objects in Scala?
For example
import scala.math._
round().getClass // errors
Is there a way to get the desired output: "scala.math.round"? So that I can be sure of round() method doesn't come from any other package I've imported.
PS. Without using Intellij IDE. The IDE shows you this info, hence there has to be a function that IDE calls to get this info.
EDIT:
For example, running these commands in scala shell
With Scala reflection (libraryDependencies += scalaOrganization.value % "scala-reflect" % scalaVersion.value in build.sbt) you can do
import scala.math._
import scala.reflect.runtime.universe._
object App {
def main(args: Array[String]): Unit = {
println(
showRaw(reify {
round(???)
})
)
}
}
Output at runtime will be
Expr(Apply(Select(Ident(scala.math.package), TermName("round")), List(Select(Ident(scala.Predef), TermName("$qmark$qmark$qmark")))))
Or you can add scalacOptions in Compile ++= Seq("-Xprint-types", "-Xprint:typer") to build.sbt.
Then compilation of
package pckg
import scala.math._
object App {
round(???)
}
will produce (at compile time)
Warning:scalac: package pckg{pckg.type} {
import scala.math._;
object App extends scala.AnyRef {
def <init>(): pckg.App.type = {
App.super{pckg.App.type}.<init>{()Object}(){Object};
(){Unit}
}{Unit};
scala.math.`package`.round{(x: Long)Long}(scala.Predef.???{Nothing}){Long}
}
}

Correction for error: - required:spray.httpx.marshalling.ToResponseMarshallable

I'm new to Scala, and trying to write a little REST API. I am using Scala 11.2, Spray 1.3.1 and akka 2.3.6.
I am basically trying to compile an example from spray.
The error I get for each of the routes is:
type mismatch; found : String("pong!!!!!!!!") required: spray.httpx.marshalling.ToResponseMarshallable
I am unsure if it is a versions incompatibility issue or I am missing a reference.
Here is my route definition taken from the spray example :
package com.Shenandoah.SBIR.httpInterface
import spray.routing.HttpService
trait HttpInterface extends HttpService {
def pingRoute = path("ping") {
get { complete("pong!!!!!!!!") }
}
def pongRoute = path("pong") {
get { complete("pong!?") }
}
def pipRoute = path("pip") {
get { complete("moonshine") }
}
def rootRoute = pingRoute ~ pongRoute ~ pipRoute
}
Here is the actor:
package com.Shenandoah.SBIR.httpInterface
import akka.actor._
class HttpInterfaceActor extends HttpInterface with Actor {
// the HttpService trait defines
// only one abstract member, which connects the services environment
// to the enclosing actor or test.
def actorRefFactory = context
def receive = runRoute(rootRoute)
}
You are probably using the dependency "io.spray" % "spray-routing" % "2.3.6" which is for Scala 2.10. There is a Spray version published without the Scala version designation, which is compiled against Scala 2.10. This is unfortunate.
Use "io.spray" %% "spray-routing" % "2.3.6" (note the double %) to pull in the dependency matching your Scala version. This will work with both Scala 2.10 and 2.11.
Looks like you are missing the default marshallers. Try adding to your imports:
import spray.httpx.marshalling.Marshaller

Reproducing a ScalaCheck test run

This was asked as a "bonus question" in https://stackoverflow.com/questions/12639454/make-scalacheck-tests-deterministic, but not answered:
Is there a way to print out the random seed used by ScalaCheck, so that you can reproduce a specific test run?
There is a hacky way: wrap a random generator to print its seed on initialization and pass it to Test.Parameters. Is there a better option?
As of today, this is possible (see scalacheck#263).
There are some nice examples here: Simple example of using seeds with ScalaCheck for deterministic property-based testing.
In short, you can do:
propertyWithSeed("your property", Some("seed")) =
forAll { ??? }
and the seed will be printed when this property fails.
There is no way to do this today. However, it will be implemented in the future, see https://github.com/rickynils/scalacheck/issues/67
This is my answer there:
Bonus question: Is there an official way to print out the random seed used by ScalaCheck, so that you can reproduce even a non-deterministic test run?
From specs2-scalacheck version 4.6.0 this is now a default behaviour:
Given the test file HelloSpec:
package example
import org.specs2.mutable.Specification
import org.specs2.ScalaCheck
class HelloSpec extends Specification with ScalaCheck {
package example
import org.specs2.mutable.Specification
import org.specs2.ScalaCheck
class HelloSpec extends Specification with ScalaCheck {
s2"""
a simple property $ex1
"""
def ex1 = prop((s: String) => s.reverse.reverse must_== "")
}
build.sbt config:
ThisBuild / scalaVersion := "2.13.0"
ThisBuild / version := "0.1.0-SNAPSHOT"
ThisBuild / organization := "com.example"
ThisBuild / organizationName := "example"
lazy val root = (project in file("."))
.settings(
name := "specs2-scalacheck",
libraryDependencies ++= Seq(
"org.specs2" %% "specs2-core" % "4.6.0",
"org.specs2" %% "specs2-matcher-extra" % "4.6.0",
"org.specs2" %% "specs2-scalacheck" % "4.6.0"
).map(_ % "test")
)
When you run the test from the sbt console:
sbt:specs2-scalacheck> testOnly example.HelloSpec
You get the following output:
[info] HelloSpec
[error] x a simple property
[error] Falsified after 2 passed tests.
[error] > ARG_0: "\u0000"
[error] > ARG_0_ORIGINAL: "猹"
[error] The seed is X5CS2sVlnffezQs-bN84NFokhAfmWS4kAg8_gJ6VFIP=
[error]
[error] > '' != '' (HelloSpec.scala:11)
[info] Total for specification HelloSpec
To reproduce that specific run (i.e with the same seed), you can take the seed from the output and pass it using the command line scalacheck.seed:
sbt:specs2-scalacheck>testOnly example.HelloSpec -- scalacheck.seed X5CS2sVlnffezQs-bN84NFokhAfmWS4kAg8_gJ6VFIP=
And this produces the same output as before.
You can also set the seed programmatically using setSeed:
def ex1 = prop((s: String) => s.reverse.reverse must_== "").setSeed("X5CS2sVlnffezQs-bN84NFokhAfmWS4kAg8_gJ6VFIP=")
Yet another way to provide the Seed is pass an implicit Parameters where the seed is set:
package example
import org.specs2.mutable.Specification
import org.specs2.ScalaCheck
import org.scalacheck.rng.Seed
import org.specs2.scalacheck.Parameters
class HelloSpec extends Specification with ScalaCheck {
s2"""
a simple property $ex1
"""
implicit val params = Parameters(minTestsOk = 1000, seed = Seed.fromBase64("X5CS2sVlnffezQs-bN84NFokhAfmWS4kAg8_gJ6VFIP=").toOption)
def ex1 = prop((s: String) => s.reverse.reverse must_== "")
}
Here is the documentation about all those various ways.
This blog also talks about this.

How to make Squeryl work with the Play! Framework?

I'm trying to learn how to make a simple database app with Play and Squeryl. I've made the Tasks app from the Play tutorial, but I want to change the model / schema so that it uses Squeryl instead of Anorm. I've been looking at different tutorials, examples and answers, but I haven't really figured out how to do this.
So, given the source code from the Play Tutorial (ScalaTodoList); how do I proceed to make it work with Squeryl?
More specifically:
How do I implement the all(), create(), and delete() methods in my model? (I'd like to use auto-incrementing ID's for the Tasks)
Which database adapter to use is currently hard coded in Build.scala and Global.scala (see below). How can I make it such that it automatically uses H2 for dev/testing and Postgres on Heroku, like it does for Anorm in the Play tutorial?
How do I make sure that it automatically creates my tables?
This is what I've done thus far
I've completed the Play ScalaTodoList Tutorial.
In project/Build.scala, object ApplicationBuild, I've added the dependencies:
// From the "Squeryl Getting Started tutorial"
val posgresDriver = "postgresql" % "postgresql" % "8.4-702.jdbc4"
val h2 = "com.h2database" % "h2" % "1.2.127"
// From the "Squeryl Getting Started tutorial"
libraryDependencies ++= Seq(
"org.squeryl" %% "squeryl" % "0.9.5",
h2
)
// From the Play tutorial
val appDependencies = Seq(
// Add your project dependencies here,
"org.squeryl" %% "squeryl" % "0.9.5", // Copied from above so that it compiles (?)
"postgresql" % "postgresql" % "8.4-702.jdbc4"
)
added app/Global.scala (taken from the SO answer mentioned above, just changed the adapter to H2):
import play.db.DB
import play.api.Application
import play.api.GlobalSettings
import org.squeryl._
import org.squeryl.adapters._
object Global extends GlobalSettings {
override def onStart(app: Application): Unit =
{
SessionFactory.concreteFactory = Some(
() => Session.create(DB.getDataSource().getConnection(),
dbAdapter));
}
override def onStop(app: Application): Unit =
{
}
val dbAdapter = new H2Adapter(); // Hard coded. Not good.
}
in app/models/Task.scala I've added imports and removed the Anorm implemetations in all(), create(), and delete().
The controller from the Play tutorial expects the all() method to return List[Task].
import org.squeryl.PrimitiveTypeMode._
import org.squeryl.Schema
import org.squeryl.annotations.Column
case class Task(id: Long, label: String)
object Task extends Schema {
val tasks = table[Task] // Inspired by Squeryl tutorial
def all(): List[Task] = {
List[Task]() // ??
}
def create(label: String) {
// ??
}
def delete(id: Long) {
// ??
}
}
The rest of the files are left as they were at the end of the Play tutorial.
Here is an example Play 2 project with Squeryl:
https://github.com/jamesward/play2bars/tree/scala-squeryl
The "Play for Scala" (MEAP) book has a chapter on Squeryl integration
http://www.manning.com/hilton/