I need to write an integration test and it requires starting a server executable. I want to make location of the server configurable, so that I could set it on my box and on integration server.
ConfigMapWrapperSuite seems to be doing exactly what I want:
#WrapWith(classOf[ConfigMapWrapperSuite])
class ConsulTest(configMap: ConfigMap) extends FlatSpec with ShouldMatchers {
val consulPath = configMap("consul.path")
"Consul" should "list keys under root" in {
...
}
But when I set my IDE (IntelliJ) to execute all tests in the project, I get an exception saying that constructor with Map parameter not found. Looking into source code of scalatest revealed:
final class ConfigMapWrapperSuite(clazz: Class[_ <: Suite]) extends Suite {
private lazy val wrappedSuite = {
val constructor = clazz.getConstructor(classOf[Map[_, _]])
constructor.newInstance(Map.empty)
}
So in contrary to what documentation says, suite must have constructor with a Map and not ConfigMap.
Ok, I changed constructor to take a Map[String,String] but now I get NoSuchElementException at val consulPath = configMap("consul.path"). Lookung up the stack down to ConfigMapWrapperSuite and I see that constructor.newInstance(Map.empty) WTF? So wrapped suite class is instantiated with empty map, and than another time, during the suite run with actual map of parameters? How do I suppose to get parameters if I'm given an empty map?
I looked up scalatest's unit tests. They are so rudimentary that actually retrieving a value from configMap is not performed.
I do not want to use ConfigMapFixture because it will make me initializing every single test with the same code.
So, how do I not only pass but also get global setting in test suite?
Scalatest version: 3.0.0-M15
Ok, answering my own question. ConfigMapWrapperSuite seems to be not used too much and essentially is broken.
Instead I've used BeforeAndAfterAllConfigMap as in here:
class ConsulTest extends FlatSpec with ShouldMatchers with OneInstancePerTest with BeforeAndAfterAllConfigMap {
var consulProcess: Process = null
override def beforeAll(conf: ConfigMap): Unit = {
consulProcess = Seq("bin/"+exe, "agent", "-advertise", "127.0.0.1", "-config-file", "bin/config.json").run()
}
override def afterAll(conf: ConfigMap): Unit = {
consulProcess.destroy()
}
You need override instance
#WrapWith(classOf[ConfigMapWrapperSuite])
class AcceptanceTest(configMap: Map[String, Any])
extends FlatSpec
with OneInstancePerTest {
override def newInstance = new AcceptanceTest(configMap)
}
Related
For a mocked class I have a method for which I would like to test whether there are no more interactions then needed, which looks similar to:
def someMethod(someMandatoryParam: Int, canBeDefaultIds: Option[Ids] = None): Future[Failures] = {...}
when I am mocking to invoke this method without the default parameter and I verify it that way:
verify(someClass).someMethod(someInt)
and then check if there was no more interactions:
verifyNoMoreInteractions(someClass)
I am getting an error that here was some unexpected interactions.
But when in implementation I change this method to use None instead of default value and verify:
verify(someClass).someMethod(someInt, None)
verifyNoMoreInteractions(someClass)
It works correctly.
Is there a problem with Mocikto and default values in Scala?
Default arguments is Scala specific feature which Java Mockito is likely not aware of. Consider how Scala code looks after -Xprint:jvm phase
abstract trait SomeClass extends Object {
def someInt(a: Option): Option = a;
<synthetic> def someInt$default$1(): Option = scala.None;
}
Notice how the default argument became just another method someInt$default$1. Try using mockito-scala which is designed with Scala in mind, for example the following test passes
import org.mockito.{ArgumentMatchersSugar, IdiomaticMockito}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
trait SomeClass {
def someInt(a: Option[Int] = None) = a
}
class MockitoScalaDefaultArgsSpec extends AnyFlatSpec with Matchers with IdiomaticMockito with ArgumentMatchersSugar {
"mockito-scala" should "handle default arguments" in {
val someClass = mock[SomeClass]
someClass.someInt()
someClass.someInt() was called
someClass wasNever calledAgain
}
}
In scala how can a unit test create a temporary directory to use as part of the testing?
I am trying to unit test a class which depends on a directory
class UsesDirectory(directory : java.io.File) {
...
}
I'm looking for something of the form:
class UsesDirectorySpec extends FlatSpec {
val tempDir = ??? //missing piece
val usesDirectory = UsesDirectory(tempDir)
"UsesDirectory" should {
...
}
}
Also, any comments/suggestions on appropriately cleaning up the resource after the unit testing is completed would be helpful.
Thank you in advance for your consideration and response.
Krzysztof's answer provides a good strategy for avoiding the need for temp directories in your tests altogether.
However if you do need UsesDirectory to work with real files, you can do something like the following to create a temporary directory:
import java.nio.file.Files
val tempDir = Files.createTempDirectory("some-prefix").toFile
Regarding cleanup, you could use the JVM shutdown hook mechanism to delete your temp files.
(java.io.File does provide deleteOnExit() method but it doesn't work on non-empty directories)
You could implement a custom shutdown hook using sys.addShutdownHook {}, and use Files.walk or Files.walkTree to delete the contents of your temp directory.
Also you may want to take a look at the better-files library, which provides a less verbose scala API for common files operations including File.newTemporaryDirectory() and file.walk()
File in Java is very cumbersome to test. There is no simple way to create some kind of virtual filesystem abstraction, which can be used for tests.
A cool way around it is to create some kind of wrapper, that can be used for stubbing and mocking.
For example:
trait FileOps { //trait which works as proxy for file
def getName(): String
def exists(): Boolean
}
object FileOps {
class FileOpsImpl(file: File) extends FileOps {
override def getName(): String = file.getName //delegate all methods you need
override def exists(): Boolean = file.exists()
}
implicit class FromFile(file: File) { //implicit method to convert File to FileOps
def toFileOps: FileOpsImpl = new FileOpsImpl(file)
}
}
Then you'd have to use it instead of File in your class:
class UsesDirectory(directory : FileOps) {
...
}
//maybe you can even create implicit conversion, but it's better to do it explicitly
val directory = new UserDirectory(file.toFileOps)
And what is benefit of that?
In your tests you can provide custom implementation of FileOps:
class UsesDirectorySpec extends FlatSpec {
val dummyFileOps = new FileOps {
override def getName(): String = "mock"
override def exists(): Boolean = true
}
//OR
val mockFileOps = mock[FileOps] //you can mock it easily since it's only trait
val usesDirectory = UsesDirectory(dummyFileOps)
"UsesDirectory" should {
...
}
}
If you use this or a similar approach, you don't even need to touch filesystem in your unit test.
Consider we have the following:
class Base { def name = "Base" }
class Successor extends Base {
override def name = "Successor"
}
I have tried to do the following (took from How to call a superclass method using Java reflection):
import java.lang.invoke.{MethodHandles, MethodHandle, MethodType}
object TestApp {
def main(args: Array[String]) {
val a = new Successor;
val h1 = MethodHandles.lookup().findSpecial(classOf[Base],
"name",
MethodType.methodType(classOf[String]),
classOf[Successor]);
println(h1.invoke(a));
}
}
but I get a runtime exception:
java.lang.IllegalAccessException: no private access for invokespecial: class Successor, from TestApp$
I was told that it is possible that Java reflection may not work correctly for Scala. Is it true? Or I simply do something wrong?
Actually, you can NOT even do it in Java. Note, in the answer of "How to call a superclass method using Java reflection", it works because the Test extends the Base: public class Test extends Base {...}.
It looks like it is possible and Java reflection works for Scala as well, I just didn't read all answers for How to call a superclass method using Java reflection.
The following code works:
object TestApp {
def main(args: Array[String]) {
val a = new Successor;
val impl_lookup = classOf[MethodHandles.Lookup].getDeclaredField("IMPL_LOOKUP")
impl_lookup.setAccessible(true)
val lkp = impl_lookup.get(null).asInstanceOf[MethodHandles.Lookup];
val h1 = lkp.findSpecial(classOf[Base],
"name",
MethodType.methodType(classOf[String]),
classOf[Successor])
println(h1.invoke(a)) // prints "Base"
println(a.name) // prints "Successor"
}
}
Thanks to Jesse Glick for this solution.
I am using Specs2 with play 2.2.1 built with Scala 2.10.2 (running Java 1.7.0_51). I have been reading about how to do setup/teardown with Specs2. I have seen examples using the "After" trait as follows:
class Specs2Play extends org.specs2.mutable.Specification {
"this is the first example" in new SetupAndTeardownPasswordAccount {
println("testing")
}
}
trait SetupAndTeardownPasswordAccount extends org.specs2.mutable.After {
println("setup")
def after = println("teardown ")
}
This works fine, except that all of my tests are using "in new WithApplication". It seems what I need is to have an object which is both a "WithApplication" and an "After". Below does not compile, but is essentially what I want:
trait SetupAndTeardownPasswordAccount extends org.specs2.mutable.After with WithApplication
So, my question is, how do I add setup/teardown to my tests which are already using "in WithApplication"? My primary concern is that all of our tests make use of fake routing like this (so they need the With Application).
val aFakeRequest = FakeRequest(method, url).withHeaders(headers).withBody(jsonBody)
val Some(result) = play.api.test.Helpers.route(aFakeRequest)
result
This is the code for WithApplication:
abstract class WithApplication(val app: FakeApplication = FakeApplication()) extends Around with Scope {
implicit def implicitApp = app
override def around[T: AsResult](t: => T): Result = {
Helpers.running(app)(AsResult.effectively(t))
}
}
It's actually quite easy to modify this to suit your needs without creating a bunch of other traits. The missing piece here is the anonymous function t, which you provide the implementation for in your tests (using WithApplication). It would be nice to make WithApplication a little more robust to be able to execute arbitrary blocks of code before and after the tests, if necessary.
One approach could be to create a similar class to WithApplication that accepts two anonymous functions setup and teardown that both return Unit. All I really need to do is modify what's happening inside AsResult.effectively(t). To keep this simple, I'm going to remove the app parameter from the parameter list, and use FakeApplication always. You don't seem to be providing a different configuration, and it can always be added back.
abstract class WithEnv(setup: => Unit, teardown: => Unit) extends Around with Scope {
implicit def implicitApp = app
override def around[T: AsResult](t: => T): Result = {
Helpers.running(app)(AsResult.effectively{
setup
try {
t
} finally {
teardown
}
})
}
}
Instead of simply calling the anonymous function t, I first call setup, then t, then teardown. The try/finally block is important because failed tests in specs2 throw exceptions, and we want to be sure that teardown will be executed no matter what the outcome.
Now you can easily setup test environments using functions.
import java.nio.files.{Files, Paths}
def createFolder: Unit = Files.createDirectories(Paths.get("temp/test"))
def deleteFolder: Unit = Files.delete("temp/test")
"check if a file exists" in new WithEnv(createFolder, deleteFolder) {
Files.exists(Paths.get("temp/test")) must beTrue
}
(This might not compile, but you get the idea.)
If your after method doesn't need anything from the WithApplication trait you can mix in your specification the AfterExample trait and define the after behaviour for the whole spec:
import org.specs2.specification._
class Specs2Play extends org.specs2.mutable.Specification with AfterExample {
"this is the first example" in new SetupAndTeardownPasswordAccount {
pending("testing")
}
trait SetupAndTeardownPasswordAccount extends WithApplication
def after = println("cleanup")
}
I have a number of use cases for this, all around the idea of interop between existing Java libraries and new Scala Code. The use case I've selected is the easiest I think.
Use Case:
I working on providing a JUnit Runner for some scala tests (so that I can get my lovely red / green bar in Eclipse)
The runner needs to have a constructor with a java class as a parameter. So in Scala I can do the following:
class MyRunner(val clazz: Class[Any]) extends Runner {
def getDescription(): Description
def run(notifier: RunNotifier)
}
When I use either
#RunWith(MyRunner)
object MyTestObject
or
#RunWith(MyRunner)
class MyTestClass
then the runner is indeed instantiated correctly, and is passed a suitable class object
Unfortunately what i want to do now is to "get hold of" the object MyTestObject, or create a MyTestClass, which are both Scala entities. I would prefer to use Scala Reflection, but I also want to use the standard Junit jar.
What I have done
The following Stackover flow questions were educational, but not the same problem. There were the nearest questions I could find
How to create a TypeTag manually?
Any way to obtain a Java class from a Scala (2.10) type tag or symbol?
Using Scala reflection with Java reflection
The discussion on Environments, Universes and Mirrors in http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html was good, and the similar documents on other scala reflection also helped. Mostly through it is about the Scala reflection.
I browsed the Scaladocs, but my knowledge of Scala reflection wasn't enough (yet) to let me get what I wanted out of them.
Edit:
As asked here is the code of the class that is being created by reflection
#RunWith(classOf[MyRunner])
object Hello2 extends App {
println("starting")
val x= "xxx"
}
So the interesting thing is that the solution proposed below using the field called MODULE$ doesn't print anything and the value of x is null
This solution works fine if you want to use plan old java reflection. Not sure if you can use scala reflection given all you will have is a Class[_] to work with:
object ReflectTest {
import collection.JavaConversions._
def main(args: Array[String]) {
val fooObj = instantiate(MyTestObject.getClass())
println(fooObj.foo)
val fooClass = instantiate(classOf[MyTestClass])
println(fooClass.foo)
}
def instantiate(clazz:Class[_]):Foo = {
val rm = ru.runtimeMirror(clazz.getClassLoader())
val declaredFields = clazz.getDeclaredFields().toList
val obj = declaredFields.find(field => field.getName() == "MODULE$") match{
case Some(modField) => modField.get(clazz)
case None => clazz.newInstance()
}
obj.asInstanceOf[Foo]
}
}
trait Foo{
def foo:String
}
object MyTestObject extends Foo{
def foo = "bar"
}
class MyTestClass extends Foo{
def foo = "baz"
}