How to use ScriptEngine in ScalaTest - scala

The following test should pass, but it doesn't
class EngineTest extends FunSuite {
test("engine should not be null") {
val manager: ScriptEngineManager = new ScriptEngineManager
val engine: ScriptEngine = manager.getEngineByName("nashorn")
assert(engine != null)
}
}
The manager.getEngineFactories() seems to be empty. Why? How to init the context?

You need to explicitly pass in a ClassLoader to the ScriptEngineManager constructor. If you don't then it uses Thread.currentThread().getContextClassLoader() which is set to something weird when running under SBT. We just pass in null in our code to get it to work. You can also pass in getClass.getClassLoader:
class EngineTest extends FunSuite {
test("engine should not be null - null classloader") {
val manager: ScriptEngineManager = new ScriptEngineManager(null)
val engine: ScriptEngine = manager.getEngineByName("nashorn")
assert(engine != null)
}
test("engine should not be null - getClass.getClassLoader classloader") {
val manager: ScriptEngineManager = new ScriptEngineManager(getClass.getClassLoader)
val engine: ScriptEngine = manager.getEngineByName("nashorn")
assert(engine != null)
}
}
Both of those tests pass for me:
[info] EngineTest:
[info] - engine should not be null - null classloader
[info] - engine should not be null - getClass.getClassLoader classloader
[info] Run completed in 186 milliseconds.
[info] Total number of tests run: 2
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.

What versions are you using? This is sbt .13.
> console
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.11.0 (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import javax.script._
import javax.script._
scala> new ScriptEngineManager().getEngineByName("scala")
res0: javax.script.ScriptEngine = scala.tools.nsc.interpreter.IMain#7078c799
scala> new ScriptEngineManager().getEngineByName("rhino")
res1: javax.script.ScriptEngine = com.sun.script.javascript.RhinoScriptEngine#5c854934
scala> new ScriptEngineManager().getEngineFactories
res2: java.util.List[javax.script.ScriptEngineFactory] = [com.sun.script.javascript.RhinoScriptEngineFactory#454ee4c0, scala.tools.nsc.interpreter.IMain$Factory#354e3bce]
Wait, you asked about test context --
Well, before I lost interest in decoding more sbt, adding to libraryDependencies:
"org.scala-lang" % "scala-compiler" % scalaVersion.value % "test",
enables locating the Scala script engine:
#Test def engines: Unit = {
import javax.script._
val all = new ScriptEngineManager().getEngineFactories
Console println s"Found ${all.size}: $all"
assert(all.size > 0)
}
No doubt there's a simple way to add runtime:full-classpath to test:full-classpath directly. Because it's the simple build tool, right?
For Nashorn on Java 8, note the location:
> set fullClasspath in Test += Attributed.blank(file(s"${util.Properties.javaHome}/lib/ext/nashorn.jar"))
[info] Defining test:fullClasspath
[info] The new value will be used by test:console, test:executeTests and 5 others.
[info] Run `last` for details.
[info] Reapplying settings...
[info] Set current project to goofy (in build file:/home/apm/goofy/)
> test
Found 1: [jdk.nashorn.api.scripting.NashornScriptEngineFactory#7fa2239d]
[info] Passed: Total 10, Failed 0, Errors 0, Passed 10
Update: https://github.com/sbt/sbt/issues/1214
Also I guess it's still considered black art:
// Somehow required to get a js engine in tests (https://github.com/sbt/sbt/issues/1214)
fork in Test := true

The only thing I had to change was to use:
fork in Test := true
as mentioned above - from here: https://github.com/sbt/sbt/issues/1214

Related

ExceptionInInitializerError in Scala unit test (Scalacheck, Scalatest)

I've written unit tests referring to DataframeGenerator example, which allows you to generate mock dataframes on the fly
After having executed the following commands successfully
sbt clean
sbt update
sbt compile
I get the errors shown in output upon running either of the following commands
sbt assembly
sbt test -- -oF
Output
...
[info] SearchClicksProcessorTest:
17/11/24 14:19:04 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
17/11/24 14:19:07 WARN SparkContext: Using an existing SparkContext; some configuration may not take effect.
17/11/24 14:19:18 WARN ObjectStore: Version information not found in metastore. hive.metastore.schema.verification is not enabled so recording the schema version 1.2.0
17/11/24 14:19:18 WARN ObjectStore: Failed to get database default, returning NoSuchObjectException
17/11/24 14:19:19 WARN ObjectStore: Failed to get database global_temp, returning NoSuchObjectException
[info] - testExplodeMap *** FAILED ***
[info] ExceptionInInitializerError was thrown during property evaluation.
[info] Message: "None"
[info] Occurred when passed generated values (
[info]
[info] )
[info] - testFilterByClicks *** FAILED ***
[info] NoClassDefFoundError was thrown during property evaluation.
[info] Message: Could not initialize class org.apache.spark.rdd.RDDOperationScope$
[info] Occurred when passed generated values (
[info]
[info] )
[info] - testGetClicksData *** FAILED ***
[info] NoClassDefFoundError was thrown during property evaluation.
[info] Message: Could not initialize class org.apache.spark.rdd.RDDOperationScope$
[info] Occurred when passed generated values (
[info]
[info] )
...
[info] *** 3 TESTS FAILED ***
[error] Failed: Total 6, Failed 3, Errors 0, Passed 3
[error] Failed tests:
[error] com.company.spark.ml.pipelines.search.SearchClicksProcessorTest
[error] (root/test:test) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 73 s, completed 24 Nov, 2017 2:19:28 PM
Things that I've tried unsuccessfully
Running sbt test with F flag to show full stacktrace (no stacktrace output appears as shown above)
Re-build the project in IntelliJ Idea
My questions are
What could be the possible cause of this error?
How can I enable the stack-trace output in SBT to be able to debug it?
EDIT-1
My unit-test class contains several methods like below
class SearchClicksProcessorTest extends FunSuite with Checkers {
import spark.implicits._
test("testGetClicksData") {
val schemaIn = StructType(List(
StructField("rank", IntegerType),
StructField("city_id", IntegerType),
StructField("target", IntegerType)
))
val schemaOut = StructType(List(
StructField("clicked_res_rank", IntegerType),
StructField("city_id", IntegerType),
))
val dataFrameGen = DataframeGenerator.arbitraryDataFrame(spark.sqlContext, schemaIn)
val property = Prop.forAll(dataFrameGen.arbitrary) { dfIn: DataFrame =>
dfIn.cache()
val dfOut: DataFrame = dfIn.transform(SearchClicksProcessor.getClicksData)
dfIn.schema === schemaIn &&
dfOut.schema === schemaOut &&
dfIn.filter($"target" === 1).count() === dfOut.count()
}
check(property)
}
}
while build.sbt looks like this
// core settings
organization := "com.company"
scalaVersion := "2.11.11"
name := "repo-name"
version := "0.0.1"
// cache options
offline := false
updateOptions := updateOptions.value.withCachedResolution(true)
// aggregate options
aggregate in assembly := false
aggregate in update := false
// fork options
fork in Test := true
//common libraryDependencies
libraryDependencies ++= Seq(
scalaTest,
typesafeConfig,
...
scalajHttp
)
libraryDependencies ++= allAwsDependencies
libraryDependencies ++= SparkDependencies.allSparkDependencies
assemblyMergeStrategy in assembly := {
case m if m.toLowerCase.endsWith("manifest.mf") => MergeStrategy.discard
...
case _ => MergeStrategy.first
}
lazy val module-1 = project in file("directory-1")
lazy val module-2 = (project in file("directory-2")).
dependsOn(module-1).
aggregate(module-1)
lazy val root = (project in file(".")).
dependsOn(module-2).
aggregate(module-2)
P.S. Please read comments on original question before reading this answer
Even the popular solution of overriding SBT's transitive dependency over faster-xml.jackson didn't work for me; in that some more changes were required (ExceptionInInitializerError was gone but some other error cropped up)
Finally (in addition to above mentioned fix) I ended up creating DataFrames in a different way (as opposed to StructType used here). I created them as
spark.sparkContext.parallelize(Seq(MyType)).toDF()
where MyType is a case class as per the schema of DataFrame
While implementing this solution, I encountered a small problem that while datatypes of schema generated from case class were correct, the nullability of fields was often mismatching; fix for this issue was found here
Here I'm blatantly admitting that I'm not sure what was the correct fix: faster-xml.jackson dependency or the alternate way of creating DataFrame, so please feel free to fill the lapses in understanding / investigating the issue
i have had a similar problem case, and after investigating I found out, that adding a lazy before a val solved my issue. My estimate is, running a Scala program with Scalatest invokes a little different initializing sequence. Where a normal scala execution initializes vals in an sourecode line numbers top-down order - having nested object {...} blocks initialized in the same way - using the same coding with Scalatest, the execution initializes the valss in nested object { ... } blocks before the vals line-number wise above the object { ... }.
This is absolutely vague I know but deferring initialization with prefixing vals with lazy could solve the test issue here.
The crucial thing here is that it doesn't occur in normal execution, only test execution, and in my case it was only occuring when using lambdas with taps in this form:
...
.tap(x =>
hook_feld_erweiterungen_hook(
abc = theProblematicVal
)
)
...

Property check should fail in Scalatest

I've created and am also using some external Scalacheck generators from Lists and appropriate types, using Gen.oneOf(List[T]) . I think it would be occasionally useful to return a placeholder for an empty value. Currently the lists are populated. How should I go about this? Do I try to append an empty type to the end of the list? If so how do I go about that? If not, how else can I get my generators to add an empty value. It seems straightforward, but I am having trouble figuring it out right now.
import org.scalatest.FlatSpec
import org.scalacheck.Gen
import org.scalacheck.Prop.exists
import org.scalatest.prop.PropertyChecks
class EventFieldGeneratorTest extends FlatSpec with PropertyChecks {
behavior of "Gen.option"
it should "occasionally return None" in {
val colors = Gen.oneOf("Blue", "Red", "Green", "Yellow")
val opt = Gen.option(colors)
val list = Gen.listOfN(20, opt)
val p1 = exists(list)(_ == None)
p1.check
}
}
Can anybody explain why my test is giving up?
Testing started at 10:31 AM ... ! Gave up after only 0 passed tests. 501 tests were discarded.
Process finished with exit code 0
How can I mark that as a failed result for ScalaTest? Is it a bad idea for me to use Flatspec?
Maybe I should be using something other than check...
Here's the documentation I used to sort it on. On the Scalatest page:
http://www.scalatest.org/user_guide/writing_scalacheck_style_properties
I don't think there's anything flawed with trying to use lists with optional values. There are just a few issues you're running in to that are giving you trouble.
It's confusing, but if you're using the Scalatest framework, you need to use the Scalatest infrastructure to use Scalacheck. So you'll need to use Scalatest matchers, and write Scalatest-flavored properties (using it's forAll), but you'll still use Scalacheck's generators directly.
For some reason the type inference between lists and Option type is giving you trouble. If you use the shouldBe matcher,
x shouldBe(None)
you'll get a relevant runtime error from Scalatest:
[info] - should occasionally return None *** FAILED ***
[info] TestFailedException was thrown during property evaluation.
[info] Message: List() was not equal to None
[info] Location: (GenTest.scala:13)
[info] Occurred when passed generated values (
[info] arg0 = List() // 5 shrinks
[info] )
[info] Run completed in 1 second, 621 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0
You shouldn't be matching a list with an Option type. You need to be matching with the Scalatest "container" matcher should contain
import org.scalatest.FlatSpec
import org.scalatest.Matchers
import org.scalacheck.Gen
import org.scalatest.prop.PropertyChecks
class EventFieldGeneratorTest extends FlatSpec with Matchers with PropertyChecks {
behavior of "Gen.option"
it should "occasionally return None" in {
val colors = Gen.oneOf("Blue","Red","Green","Yellow")
val opt = Gen.option(colors)
val list = Gen.listOfN(20,opt)
forAll(list) { (xs: List[Option[String]]) =>
xs should contain (None)
}
}
}
This gives you a successful property check:
[info] EventFieldGeneratorTest:
[info] Gen.option
[info] - should occasionally return None
[info] ScalaTest
[info] Run completed in 1 second, 9 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[info] Passed: Total 1, Failed 0, Errors 0, Passed 1
More on Scalatest matchers
http://www.scalatest.org/user_guide/using_matchers

Why Mockito doesn't handle default Scala parameters properly?

I have a code like
test("mockito test") {
class ToTest {
def run(maybe: Option[Int], q: Option[Int] = None): Int = 42
}
val mockTest = mock[ToTest]
when(mockTest.run(None, None)).thenReturn(98)
mockTest.run(None)
verify(mockTest, times(1)).run(None, None)
}
Which fails with
[info] - mockito test *** FAILED ***
[info] org.mockito.exceptions.verification.junit.ArgumentsAreDifferent: Argument(s) are different! Wanted:
[info] toTest$1.run(None, None);
[info] -> at xxx$$anonfun$3.apply$mcV$sp(xxx.scala:55)
[info] Actual invocation has different arguments:
[info] toTest$1.run(None, null);
Or another scenario
test("mockito test") {
class ToTest {
def run(maybe: Option[Int], q: Int = 5): Int = 42
}
val mockTest = mock[ToTest]
when(mockTest.run(None, 5)).thenReturn(101)
mockTest.run(None)
verify(mockTest, times(1)).run(None, 5)
}
which fails with
[info] - mockito test *** FAILED ***
[info] org.mockito.exceptions.verification.junit.ArgumentsAreDifferent: Argument(s) are different! Wanted:
[info] toTest$1.run(None, 5);
[info] -> at xxx$$anonfun$3.apply$mcV$sp(xxx.scala:55)
[info] Actual invocation has different arguments:
[info] toTest$1.run(None, 0);
I guess it's because there are no default parameters in Java. Is there any workaround for it?
Thank you.
I guess that's because of CGLIB (or Byte Buddy in case of 2.0 beta) generates the code in that case, not Scala compiler, hence the default parameters will be always null.
A workaround could be (at least in some cases) to use spy instead:
val mockTest = spy(classOf[ToTest])
Sorry, no sugar syntax for it in ScalaTest.

Play test-only doesn't ignore tests

I have a play application and I need to ignore my functional tests when I compile and build, then later run only the integration tests.
This is my test code:
ApplicationSpec.scala
#RunWith(classOf[JUnitRunner])
class ApplicationSpec extends Specification {
"Application" should {
"send 404 on a bad request" in new WithApplication {
route(FakeRequest(GET, "/boum")) must beNone
}
}
IntegrationSpec.scala
#RunWith(classOf[JUnitRunner])
class IntegrationSpec extends Specification {
"Application" should {
"work from within a browser" in {
running(TestServer(9000), FIREFOX) { browser =>
browser.goTo("http://localhost:9000/app")
browser.pageSource must contain("Your new application is ready.")
}
}
} section "integration"
}
The docs tells me I can use something like this from the command line:
play "test-only -- exclude integration"
The only problem is that this doesn't actually exclude any tests and my integration tests invoke firefox and start running. What am I doing wrong? How can I exclude the integration tests and then later run them by themselves?
sbt's Testing documentation describes several ways to define separate test configurations.
For instance, the Additional test configurations with shared sources example could be used in this situation:
In this approach, the sources are compiled together using the same classpath and are packaged together. However, different tests are run depending on the configuration.
In a default Play Framework 2.2.2 application created with play new, add a file named project/Build.scala with this content:
import sbt._
import Keys._
object B extends Build {
lazy val root =
Project("root", file("."))
.configs(FunTest)
.settings(inConfig(FunTest)(Defaults.testTasks) : _*)
.settings(
libraryDependencies += specs,
testOptions in Test := Seq(Tests.Filter(unitFilter)),
testOptions in FunTest := Seq(Tests.Filter(itFilter))
)
def itFilter(name: String): Boolean = (name endsWith "IntegrationSpec")
def unitFilter(name: String): Boolean = (name endsWith "Spec") && !itFilter(name)
lazy val FunTest = config("fun") extend(Test)
lazy val specs = "org.specs2" %% "specs2" % "2.0" % "test"
}
To run standard unit tests:
$ sbt test
Which produces:
[info] Loading project definition from /home/fernando/work/scratch/so23160453/project
[info] Set current project to so23160453 (in build file:/home/fernando/work/scratch/so23160453/)
[info] ApplicationSpec
[info] Application should
[info] + send 404 on a bad request
[info] + render the index page
[info] Total for specification ApplicationSpec
[info] Finished in 974 ms
[info] 2 examples, 0 failure, 0 error
[info] Passed: Total 2, Failed 0, Errors 0, Passed 2
[success] Total time: 3 s, completed Apr 22, 2014 12:42:37 PM
To run tests for the added configuration (here, "fun"), prefix it with the configuration name:
$ sbt fun:test
Which produces:
[info] Loading project definition from /home/fernando/work/scratch/so23160453/project
[info] Set current project to so23160453 (in build file:/home/fernando/work/scratch/so23160453/)
[info] IntegrationSpec
[info] Application should
[info] + work from within a browser
[info] Total for specification IntegrationSpec
[info] Finished in 0 ms
[info] 1 example, 0 failure, 0 error
[info] Passed: Total 1, Failed 0, Errors 0, Passed 1
[success] Total time: 6 s, completed Apr 22, 2014 12:43:17 PM
You can also test only a particular class, like this:
$ sbt "fun:testOnly IntegrationSpec"
See this example in GitHub.

Make tests in multi project sbt projects run only if tests pass in dependent projects

Assuming a multiproject SBT project with a foo-project and bar-project, such that foo-project depends on bar-project for code etc.
I would like tests in foo-project to run iff the tests in bar-project pass.
How?
You may provide explicit dependencies between projects. For example root -> A -> B
Test case on GitHub. Project definition:
val commonSettings = Seq(libraryDependencies += "org.scalatest" %% "scalatest" % "1.9.1")
lazy val a: Project = (project in file("a")) settings(commonSettings: _*) settings(
name := "a",
test in Test <<= test in Test dependsOn (test in Test in b)
)
lazy val b: Project = (project in file("b")) settings(commonSettings: _*) settings(
name := "b"
)
lazy val root: Project = (project in file(".")) settings(commonSettings: _*) settings(
name := "root",
test in Test <<= test in Test dependsOn (test in Test in a)
)
Beginning from B and complete them successful:
ezh#mobile ZZZZZZ % sbt-0.13
[info] Set current project to root (in build file:/home/ezh/ZZZZZZ/)
> root/test
[info] Compiling 1 Scala source to /home/ezh/ZZZZZZ/b/target/scala-2.10/test-classes...
[info] TestSpecB:
[info] This test
[info] - should fail
[info] Passed: Total 1, Failed 0, Errors 0, Passed 1
[info] Compiling 1 Scala source to /home/ezh/ZZZZZZ/a/target/scala-2.10/test-classes...
[info] TestSpecA:
[info] This test
[info] - should succeed
[info] Passed: Total 1, Failed 0, Errors 0, Passed 1
[info] Passed: Total 0, Failed 0, Errors 0, Passed 0
[info] No tests to run for root/test:test
[success] Total time: 5 s, completed 28.11.2013 16:20:12
Beginning from B but fail:
ezh#mobile ZZZZZZ % sbt-0.13
[info] Set current project to root (in build file:/home/ezh/ZZZZZZ/)
> test
[info] Compiling 1 Scala source to /home/ezh/ZZZZZZ/b/target/scala-2.10/test-classes...
[info] TestSpecB:
[info] This test
[info] - should fail *** FAILED ***
[info] 2 did not equal 3 (Test.scala:5)
[error] Failed: Total 1, Failed 1, Errors 0, Passed 0
[error] Failed tests:
[error] TestSpecB
[error] (b/test:test) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 3 s, completed 28.11.2013 16:20:35
>
as already noted this is probably evil, however this should probably work:
import sbt._
import sbt.Keys._
object Build extends Build {
lazy val projectA = project
lazy val myTest = taskKey[Seq[Option[Tests.Output]]]("my test")
lazy val root: Project = project in file(".") settings (myTest <<= myTestTask) dependsOn projectA
def myTestTask = Def.task {
val state: State = Keys.state.value
val log: Logger = streams.value.log
val extracted = Project.extract(state)
import extracted._
def noTestsMessage(scoped: ScopedKey[_])(implicit display: Show[ScopedKey[_]]): String =
"No tests to run for " + display(scoped)
def f(ref: ProjectReference) = for {
state Pair Value(r) <- Project.runTask(executeTests in(ref, Test), state)
_ = Tests.showResults(log, r, noTestsMessage(test in ref))
} yield r
val depsTests = currentProject.dependencies.map(_.project).map(f)
val passed = depsTests.forall(_.forall(_.overall == TestResult.Passed))
if (passed) depsTests :+ f(ThisProject) else depsTests
}
}
http://scastie.org/3319