Run all tests without the #RunWith(classOf[JUnitRunner]) dance? - scala

Is there any way to set up IntelliJ's JUnit "Run All Tests" command to automatically pick up Scala Specs2? i.e. removing the boilerplate annotation in this snippet:
#RunWith(classOf[JUnitRunner])
class MySpec extends Specification
It's very irritating to have to remember to add this.
I've seen SpecificationWithJUnit but that is also a bit of a hack (and is incompatible with TestKit). I'm looking for a maven/sbt/intelliJ side solution.

With Intellij, you shouldn't need the annotation to execute your specifications, because it has its own specs2 runner. I'm using IntelliJ 123.100 with a recent version of the Scala plugin (82 I think) and things work ok (except for this issue).

Use #RunWith(classOf[JUnitPlatform]) instead JUnitRunner
Maybe this could help you:
import org.junit.jupiter.api.{DisplayName, Test}
import org.junit.platform.runner.JUnitPlatform
import org.junit.runner.RunWith
import org.scalatest.{BeforeAndAfterAll, Matchers}
import org.scalatest.junit.JUnitSuite
#RunWith(classOf[JUnitPlatform])
class Junit5Test extends JUnitSuite with Matchers with BeforeAndAfterAll {
override def beforeAll: Unit = { println(">>> beforeAll <<< ") }
#Test
#DisplayName("Example with JUnitSuite")
#throws(classOf[RuntimeException])
def throwsExceptionWhenCalled() {
println("Запуск теста...")
assertThrows[RuntimeException] { throw new RuntimeException }
}
}
And build.sbt file:
val junitJupiter = "5.2.0"
val junitPlatform = "1.2.0"
libraryDependencies ++= Seq(
"junit" % "junit" % "4.12" % Test,
"org.junit.jupiter" % "junit-jupiter-api" % junitJupiter % Test,
"org.junit.jupiter" % "junit-jupiter-engine" % junitJupiter % Test,
"org.junit.jupiter" % "junit-jupiter-params" % junitJupiter % Test,
"org.junit.platform" % "junit-platform-launcher" % junitPlatform % Test,
"org.junit.platform" % "junit-platform-engine" % junitPlatform % Test,
"org.junit.platform" % "junit-platform-runner" % junitPlatform % Test,
)

Related

Scala : play is not recognizing the test components

I am transitioning from Java to Scala. I have written a simple test to render a view. Like :
import org.scalatestplus.play.PlaySpec
import org.scalatest._
import org.slf4j.LoggerFactory
import play.test.WithApplication
class EvTemplateTests extends PlaySpec{
implicit lazy val log = LoggerFactory.getLogger(getClass)
//run your test//run your test
"render eval template" in {
val html = views.html.index("Hello")
contentType(html) must equalTo("text/html")
contentAsString(html) must contain("Welcome to Play!")
}
}
When compiling, looks like it is not finding "index","contentType", "contentAsString" etc.Looks like, the project is using the libraries:
lazy val thirdPartyDependencies = Seq(
jdbc,
"com.typesafe.play" %% "anorm" % "2.4.0",
"com.typesafe.play" %% "play-mailer" % "3.0.1",
"com.microsoft.sqlserver" % "mssql-jdbc" % "6.4.0.jre8",
"io.swagger" %% "swagger-play2" % "1.5.0", // This version adds Play 2.4 support.
// ScalaTest+ Play (have to use non-release 1.4.0-M4 version for now as it is only compatible with Play 2.4)
"org.scalatestplus" %% "play" % "1.4.0-M4" % "test",
"org.mockito" % "mockito-core" % "1.10.19" % "test"
)
May I get any insight?
You can start from here:
import controllers.AssetsFinder
import org.specs2.mutable.Specification
import play.api.Application
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.mvc._
import play.api.test._
import play.api.test.Helpers._
class EvTemplateTests
extends Specification
with DefaultAwaitTimeout
with FutureAwaits
with Results {
val application: Application = GuiceApplicationBuilder().build()
"render eval template" in new WithApplication(app = application) {
implicit val assetsFinder = app.injector.instanceOf[AssetsFinder]
val html = views.html.index("Hello")
contentType(html) mustEqual "text/html"
contentAsString(html) must contain("Hello")
}
}
add this after jdbc in LibraryDependencies: specs2 % Test
Most important part of test setup here is implicit AssetFinder that derived from GuiceApplicationBuilder:
val application: Application = GuiceApplicationBuilder().build()
AssetFinder is really important part of view testing in PlayFramework

Mocking a vararg tuple using mockito

I want to mock this method
def zadd[V: ByteStringSerializer](key: String, scoreMembers: (Double, V)*): Future[Long]
Tried this
mock.zadd(anyString(), Seq((anyDouble(), any String()), (anyDouble(), anyString())): _*)
doesnt work because mockito says 3 matchers expected, but got 5 instead.
so I try using How to properly match varargs in Mockito
but, I cant even use the code listed in that example
ArgumentMatchers.<String>any() gets flagged as error in my IDE saying not recognized type String
mockito-scala supports varargs out-of-the-box, for example
import cats.implicits._
import org.mockito.ArgumentMatchersSugar
import org.mockito.cats.IdiomaticMockitoCats
import org.mockito.scalatest.IdiomaticMockito
import org.scalatest._
import org.scalatest.concurrent.ScalaFutures
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
trait Foo {
def zadd(key: String, scoreMembers: (Double, String)*): Future[Long]
}
class HelloSpec extends FlatSpec
with Matchers
with IdiomaticMockito
with IdiomaticMockitoCats
with ScalaFutures
with ArgumentMatchersSugar {
"Foo" should "mock varargs" in {
val foo = mock[Foo]
foo.zadd("", *) returnsF 42L
foo.zadd("bar", (7.7, "qux")) returnsF 89L
foo.zadd("", (1.1, "")).futureValue should be (42L)
foo.zadd("bar", (7.7d, "qux")).futureValue should be (89L)
}
}
where
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.0.8",
"org.mockito" %% "mockito-scala" % "1.5.13",
"org.mockito" %% "mockito-scala-scalatest" % "1.5.13",
"org.mockito" %% "mockito-scala-cats" % "1.5.13",
"org.typelevel" %% "cats-core" % "2.0.0-M4"
)

Expect a specific instance for mock in Scalamock

Why can I not tell a mock that it should expect an instance of a class without explicitly giving the type? Here is what I mean:
val myClass = new MyClass(...)
val traitMock = mock[MyTrait]
(traitMock.mymethod _).expects(myClass).returning(12.3)
does not work, while
val myClass: MyClass = new MyClass(...)
val traitMock = mock[MyTrait]
(traitMock.mymethod _).expects(myClass).returning(12.3)
does work. How come the type can not be inferred?
My testing part in build.sbt is
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.0.0" % "test"
exclude("org.scala-lang", "scala-reflect")
exclude("org.scala-lang.modules", "scala-xml")
)
libraryDependencies += "org.scalamock" %% "scalamock-scalatest-support" % "3.3.0" % "test"
Since I was asked for MyClass (it is SpacePoint here):
trait SpacePoint {
val location: SpaceLocation
}
val sp = new SpacePoint {
override val location: SpaceLocation = new SpaceLocation(DenseVector(1.0, 1.0))
}
So actually it works for me. Let me mention that type inference in the code:
val myClass = new MyClass(...)
has nothing to do with ScalaMock but is guaranteed by scala itself. Below I will specify working sample with library versions and sources of the classes.
Testing libraries:
"org.scalatest" %% "scalatest" % "2.2.4" % "test",
"org.scalamock" %% "scalamock-scalatest-support" % "3.2.2" % "test"
Source code of classes:
class MyClass(val something: String)
trait MyTrait {
def mymethod(smth: MyClass): Double
}
Source code of test:
import org.scalamock.scalatest.MockFactory
import org.scalatest.{Matchers, WordSpec}
class ScalamockTest extends WordSpec with MockFactory with Matchers {
"ScalaMock" should {
"infers type" in {
val myClass = new MyClass("Hello")
val traitMock = mock[MyTrait]
(traitMock.mymethod _).expects(myClass).returning(12.3)
traitMock.mymethod(myClass) shouldBe 12.3
}
}
}
Hope it helps. Will be ready to update answer once you provide more details.

SBT incorrect order of compilation

TL/DR: Checkout last two commits and run sbt clean compile: https://github.com/mirelon/akka-in-action/tree/json/chapter2
There is RestInterface.scala:
package com.goticks
import akka.actor._
import spray.routing._
import spray.http.StatusCodes
import spray.httpx.SprayJsonSupport._
import spray.routing.RequestContext
import akka.util.Timeout
import scala.concurrent.duration._
import scala.language.postfixOps
class RestInterface extends HttpServiceActor
with RestApi {
def receive = runRoute(routes)
}
trait RestApi extends HttpService { actor: Actor =>
import context.dispatcher
import com.goticks.TicketProtocol._
implicit val timeout = Timeout(10 seconds)
import akka.pattern.ask
def routes: Route =
path("events") {
get { requestContext =>
context.actorOf(Props[Resu]).ask(GetEvents)
}
}
}
class Responder(requestContext:RequestContext) extends Actor {
import TicketProtocol._
def receive = {
case Events(events) =>
requestContext.complete(StatusCodes.OK, events)
self ! PoisonPill
}
}
and Resu.scala (note that Resu is alphabetically after RestInterface)
package com.goticks
import akka.actor.Actor
class Resu extends Actor {
import TicketProtocol._
import spray.json._
def receive = {
case GetEvents => {
println(Event(event = "E").toJson)
}
}
}
object TicketProtocol {
import spray.json._
case class Event(event:String)
case object GetEvents
case class Events(events:List[Event])
object Event extends DefaultJsonProtocol {
implicit val format = jsonFormat1(Event.apply)
}
}
build.sbt:
name := "goticks"
version := "0.1-SNAPSHOT"
organization := "com.goticks"
scalaVersion := "2.11.1"
libraryDependencies ++= {
val akkaVersion = "2.3.4"
val sprayVersion = "1.3.1"
Seq(
"com.typesafe.akka" %% "akka-actor" % akkaVersion,
"io.spray" %% "spray-can" % sprayVersion,
"io.spray" %% "spray-routing" % sprayVersion,
"io.spray" %% "spray-json" % "1.2.6"
)
}
build.properties;
sbt.version=0.13.7
plugins.sbt:
resolvers += Classpaths.typesafeResolver
resolvers += "sbt-idea" at "http://mpeltonen.github.com/maven/"
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.6.0")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.11.2")
addSbtPlugin("com.typesafe.sbt" % "sbt-start-script" % "0.10.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-multi-jvm" % "0.3.8")
Compilation issue
When I run sbt clean compile, everything is ok. But when I refactor the Resu class into Ress (note that Ress is alphabetically before RestInterface) (also rename its file, the diff can be viewed here: https://github.com/mirelon/akka-in-action/commit/583ca801fb7d1564024eee2f98d57f03ecacc6e5), then there is a compilation error:
[error] /home/miso/IdeaProjects/akka-in-action/chapter2/src/main/scala/com/goticks/Ress.scala:12: Cannot find JsonWriter or JsonFormat type class for com.goticks.TicketProtocol.Event
[error] println(Event(event = "E").toJson)
[error] ^
[error] one error found
[error] (compile:compile) Compilation failed
Clearly there is an implicit json writer missing. Could it be due to incorrect order of compiling? Could sbt compile the classes in alphabetical order, ignoring imports?
Yes, sbt always compiles in alphabetical order. The issue is sbt has no idea the dependencies between files until it runs the compiler.
What you're seeing is the scala compiler itself is dependent on the ordering of source files. Sbt always sorts source files so you can at least work around these issues by placing code in an ordering that works.
I'm not 100% sure why you're hitting such an issue from some implicits + macro hackery, but that could be wrong.

Scala enumeration serialization in jersey/jackson is not working for me

I've read the jackson-module-scala page on enumeration handling (https://github.com/FasterXML/jackson-module-scala/wiki/Enumerations). Still I'm not getting it to work. The essential code goes like this:
#Path("/v1/admin")
#Produces(Array(MediaType.APPLICATION_JSON + ";charset=utf-8"))
#Consumes(Array(MediaType.APPLICATION_JSON + ";charset=utf-8"))
class RestService {
#POST
#Path("{type}/abort")
def abortUpload(#PathParam("type") typeName: ResourceTypeHolder) {
...
}
}
object ResourceType extends Enumeration {
type ResourceType = Value
val ssr, roadsegments, tmc, gab, tne = Value
}
class ResourceTypeType extends TypeReference[ResourceType.type]
case class ResourceTypeHolder(
#JsonScalaEnumeration(classOf[ResourceTypeType])
resourceType:ResourceType.ResourceType
)
This is how it's supposed to work, right? Still I get these errors:
Following issues have been detected:
WARNING: No injection source found for a parameter of type public void no.tull.RestService.abortUpload(no.tull.ResourceTypeHolder) at index 0.
unavailable
org.glassfish.jersey.server.model.ModelValidationException: Validation of the application resource model has failed during application initialization.
[[FATAL] No injection source found for a parameter of type public void no.tull.RestService.abortUpload(no.tull.ResourceTypeHolder) at index 0.; source='ResourceMethod{httpMethod=POST, consumedTypes=[application/json; charset=utf-8], producedTypes=[application/json; charset=utf-8], suspended=false, suspendTimeout=0, suspendTimeoutUnit=MILLISECONDS, invocable=Invocable{handler=ClassBasedMethodHandler{handlerClass=class no.tull.RestService, handlerConstructors=[org.glassfish.jersey.server.model.HandlerConstructor#7ffe609f]}, definitionMethod=public void no.tull.RestService.abortUpload(no.tull.ResourceTypeHolder), parameters=[Parameter [type=class no.tull.ResourceTypeHolder, source=type, defaultValue=null]], responseType=void}, nameBindings=[]}']
at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:467)
at org.glassfish.jersey.server.ApplicationHandler.access$500(ApplicationHandler.java:163)
at org.glassfish.jersey.server.ApplicationHandler$3.run(ApplicationHandler.java:323)
at org.glassfish.jersey.internal.Errors$2.call(Errors.java:289)
at org.glassfish.jersey.internal.Errors$2.call(Errors.java:286)
I have also assembled a tiny runnable project (while trying to eliminate any other complications) that demonstrates the problem: project.tgz
Update: Created an sbt-file to see if gradle was building a strange build. Got the same result, but this is the build.sbt:
name := "project"
version := "1.0"
scalaVersion := "2.10.4"
val jacksonVersion = "2.4.1"
val jerseyVersion = "2.13"
libraryDependencies ++= Seq(
"com.fasterxml.jackson.core" % "jackson-annotations" % jacksonVersion,
"com.fasterxml.jackson.core" % "jackson-databind" % jacksonVersion,
"com.fasterxml.jackson.jaxrs" % "jackson-jaxrs-json-provider" % jacksonVersion,
"com.fasterxml.jackson.jaxrs" % "jackson-jaxrs-base" % jacksonVersion,
"com.fasterxml.jackson.module" % "jackson-module-scala_2.10" % jacksonVersion,
"org.glassfish.jersey.containers" % "jersey-container-servlet-core" % jerseyVersion
)
seq(webSettings :_*)
libraryDependencies ++= Seq(
"org.eclipse.jetty" % "jetty-webapp" % "9.1.0.v20131115" % "container",
"org.eclipse.jetty" % "jetty-plus" % "9.1.0.v20131115" % "container"
)
... and this is the project/plugins.sbt:
addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "0.9.0")
You seem to possibly have a few problems with your tarball.
You need to add some Scala modules to Jackson to be able to use any Scala functionality. That can be done by doing this:
val jsonObjectMapper = new ObjectMapper()
jsonObjectMapper.registerModule(DefaultScalaModule)
val jsonProvider: JacksonJsonProvider = new JacksonJsonProvider(jsonObjectMapper)
According to this working jersey-jackson example. You also need to inject org.glassfish.jersey.jackson.JacksonFeature into Jersey which is found in jersey-media-json-jackson. My RestApplication.scala came out like this
import javax.ws.rs.core.Application
import javax.ws.rs.ext.{ContextResolver, Provider}
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.google.common.collect.ImmutableSet
import org.glassfish.jersey.jackson.JacksonFeature
#Provider
class ObjectMapperProvider extends ContextResolver[ObjectMapper] {
val defaultObjectMapper = {
val jsonObjectMapper = new ObjectMapper()
jsonObjectMapper.registerModule(DefaultScalaModule)
jsonObjectMapper
}
override def getContext(typ: Class[_]): ObjectMapper = {
defaultObjectMapper
}
}
class RestApplication extends Application {
override def getSingletons: java.util.Set[AnyRef] = {
ImmutableSet.of(
new RestService,
new ObjectMapperProvider,
new JacksonFeature
)
}
}
The real issue, though, is the #PathParam annotation. This code path doesn't invoke Jackson at all. However, what's interesting is that Jersey appears to generically support parsing to any type that has a constructor of a single string. So if you modify your ResourceTypeHolder you can get the functionality you want after all.
case class ResourceTypeHolder(#JsonScalaEnumeration(classOf[ResourceTypeType]) resourceType:ResourceType.ResourceType) {
def this(name: String) = this(ResourceType.withName(name))
}
You might be able to add generic support for enum holders to Jersey as an injectable provider. However, that hasn't come up in dropwizard-scala, a project that would suffer the same fate as it uses Jersey too. Thus I imagine it's either impossible, or simply just not common enough for anyone to have done the work. When it comes to enum's, I tend to keep mine in Java.