I'm trying to write an integration test for a small command line app I'm writing with Scala and SBT. My app would usually be run from the SBT prompt like so:
> run "my arg"
The argument "my arg" is accessed in the app with args(0). For an integration test how can I simulate calling run with an argument and asserting console output?
Your app needs to have an object with main method that takes Array[String] as parameter.
It looks like this
object Main extends App {
print("hi, " + args(0))
}
or like this
object Main {
def main(args: Array[String]) = print("hi, " + args(0))
}
Anyway you definitely have this kind of entry point if you can do > run "my arg" in sbt.
It is just an object with a method called main that you can call wherever you want. Just import it and use:
Main.main(Array("my arg"))
that would print the text to the console when executed. We need to redirect the console output to some other stream to be able to verify it.
Using answer from Redirect stdout in another thread you can come up with something like this:
val baos = new ByteArrayOutputStream
val ps = new PrintStream(baos)
Console.withOut(ps)(Main.main(Array("my arg")))
val output = baos.toString
And you can do all sort of tests on output value
You can then create a helper method to handle this for you
def outputFor(args: String*): String = {
val baos = new ByteArrayOutputStream
val ps = new PrintStream(baos)
Console.withOut(ps)(Main.main(args.toArray))
baos.toString
}
And then easly test your app
"My app" should "greet me" {
outputFor("harryg") shouldBe "hi, harryg"
}
Just to clarify, the whole solution has nothing to do with sbt itself, we directly call the program in a similar way that sbt would do it.
Related
After Reading the official flink testing documentation (https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/stream/testing.html)
I was able to develop tests for a ProcessFunction, using a Test Harness, something like this:
pendingPartitionBuilder = new PendingPartitionBuilder(":::some_name", "")
testHarness =
new OneInputStreamOperatorTestHarness[StaticAdequacyTilePublishedData, PendingPartition](
new ProcessOperator[StaticAdequacyTilePublishedData, PendingPartition](pendingPartitionBuilder)
)
testHarness.open()
now, I’m trying to do the same for a ProcessAllWindowFunction, that looks like this:
class MapVersionValidationDistributor(batchSize: Int) extends
ProcessAllWindowFunction[MapVersionValidation, Seq[StaticAdequacyTilePublishedData],TimeWindow] {
lazy val state: ValueState[Long] = getRuntimeContext .getState(new ValueStateDescriptor[Long]("latestMapVersion", classOf[Long]))
(...)
First I realized I can’t use TestHarness for ProcessAllWindowFunction, because it doesn’t have a processElement method. In this case, what unit test strategy should I follow?
EDIT: At the moment my test code looks like this:
val collector = mock[Collector[Seq[StaticAdequacyTilePublishedData]]]
val mvv = new MapVersionValidationDistributor(1)
val input3 = Iterable(new MapVersionValidation("123",Seq(TileValidation(1,true,Seq(1,3,4)))))
val ctx = mock[mvv.Context]
val streamContext = mock[RuntimeContext]
mvv.setRuntimeContext(streamContext)
mvv.open(mock[Configuration])
mvv.process(ctx,input3,collector)
and I'm getting this error:
Unexpected call: <mock-3> RuntimeContext.getState[T](ValueStateDescriptor{name=latestMapVersion, defaultValue=null, serializer=null}) Expected: inAnyOrder { }
You don't really need test harness to unit test the process method of the ProcessAllWindowFunction. The process function takes 3 arguments: Context, Iterable[IN], Collector[OUT]. You can use some library depending on the language used to mock the Context. You can also easily implement or mock the Collector depending on your prerefences here. And the Iterable[IN] is just an Iterable containing the elements of Your window, that would be passed to the function after the window is triggered.
I am trying to compile and execute a "hello world" program using twitter util-eval library. But not able to get results printed.
My intention is not just to compile and execute hello world example, large scala files with dependencies should compile and run.
import com.twitter.util.Eval
object ScalaCompiler3 {
def main(args: Array[String]): Unit = {
val eval = new Eval()
val fileContents = "class Test {\n\n println (\"Hello World!\")\n\n}"
val compile = eval.apply[Unit](fileContents)
println(compile)
}
}
How do I execute the code and see the results? am not able to get proper API documentation for util-eval. Using util-eval_2.11-6.43.0.jar taken from maven
As erip mentioned in the comments, the source string you're compiling makes a class, Test, but since you never instantiate the class it never runs the code within.
If you replace:
val fileContents = "class Test {\n\n println (\"Hello World!\")\n\n}"
with:
val fileContents = "println(\"Hello World!\")\n\n}"
That will execute the code you're looking to execute. Best of luck with your project!
The contents of myfile.scala are as follows :
// println("print this line")
object myObj {
def main(args: Array[String]): Unit = {
println("Hello, world!")
}
}
If I run : scala myfile.scala, it prints : Hello, world
If I uncomment the first println stmt, and run : scala myfile.scala,
it only prints : print this line ,
and does not print hello-world stmt.
Why is this so? I find it very confusing. I tried to search the archives, but could not find any answers.
When the scala command sees a top level statement (not in a class or object) in the file, it runs the file as a script, starting at the first line and moving down. You main method never gets called because you never call it, just define it. When your file doesn't contain any top level statements but it does contain a main object, it will run the main method as the entry point to the program.
Earlier I runned val pb = Process("""java -version""") and it gave me an exitValue of 0 as expected but code below runs process without exiting or blocking, so how can I get exitValue, my requirement actually is how to get status of a process that runs in background without stopping.
object Sample extends App {
import scala.sys.process.Process
val pb = Process("""java -jar common-api_2.11-1.3-one-jar.jar""")
val x = pb.run
print( "Exit value :" + x.exitValue )
}
You can get all the std output of a running process by passing a ProcesLogger to the run method:
e.g.
val logger = ProcessLogger((msg: String) ⇒ println(msg))
val x = pb.run(logger)
will print all output to the System.out. -but you can pass a function that would parse and evaluate the output of the process to extract some kind of state meaningful to your application. You can also pass a different function for statndard and error output. Have a look at ProcessLogger.apply variants.
first of all, i like to say that i have read the other two questions regarding the same problem, and the solutions outlined in them did not help me. i tried cleaning, rebuilding, re-opening but it ddnt work out. I use eclipse for scala dev. This is the sample prog that i am trying to get an output from, its just casbah.
package com.examples.casbah
import com.novus.casbah.mongodb.MongoConnection
object newObject {
def main(args: Array[String]): Unit = {
val mongoConn = MongoConnection()
val mongoDB = mongoConn("casbah_test")
val builder = MongoDBObject.newBuilder
builder += "foo" -> "bar"
builder += "x" -> "y"
builder += ("pie" -> 3.14)
builder += ("spam" -> "eggs", "mmm" -> "bacon")
// You must explicitly cast the result to a DBObject
// to receive it as such; you can also request it 'asDBObject'
val newObj = builder.result.asDBObject
Console.println(("A", "ProGGram"))
}
}
I get the following error in the eclipse error log:
An unexpected exception was thrown
this is the stack trace
i read one comment about trying to run via clicking on the root of source project. But i only see Run as Java Applet and Run as Java Application. There is no option to run as Scala application. I have to run it using Alt+Shift+X S
TIA.
The best place for questions like this is the Scala IDE user mailing list.