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
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?
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}
}
}
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
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.
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/