I have the following code(which I've simplified for the purpose of the question):
def openFile(directory: File): Try[String] = {
var input = ""
do {
input = readLine("prompt>")
println("alibaba.txt: 100%")
} while(input != ":quit")
}
The workflow is this:
the user gets a prompt:
prompt>
The user writes alibaba and then presses enter
The user sees:
alibaba.txt: 100%
prompt>
Everything:
prompt>alibaba
alibaba.txt: 100%
prompt>
Now, I want to test it.
I wrote the following code to test the user interaction:
test("simulate user input from readline") {
val prompt = new Prompt()
prompt.openFile(new File("../resources"))
val in = new ByteArrayInputStream("alibaba\n".getBytes)
System.setIn(in)
val scanner: Scanner = new Scanner(System.in)
val programResponse: String = scanner.nextLine()
println("programResponse: " + programResponse)
System.setIn(System.in)
assert(programResponse == "alibaba.txt: 100%")
}
However, I'm getting this result and I'm confused:
"alibaba[]" did not equal "alibaba[.txt: 100%]"
So how can I make the test simulate the user interaction?
How can I read what my program wrote?
IMO you should structure your code in a way that it is simply testable meaning that you should extract IO to higher abstractions.
For demonstration purpose I slightly modified your example to the following code:
import java.util.Scanner
object YourObject {
def consoleMethod(in: () => String = new Scanner(System.in).nextLine,
out: String => Unit = System.out.println): Unit = {
var input = ""
do {
out("prompt>")
input = in()
out("alibaba.txt: 100%")
} while (input != ":quit")
}
}
Let's break it down:
in: () => String = new Scanner(System.in).nextLine stands for our source of the user input. By default it is System.in.
out: String => Unit = System.out.println stands for our output source. By default it is System.out
Let's test the scenario when user entered ":quit" right away:
import org.scalatest.{Matchers, WordSpec}
class Test extends WordSpec with Matchers {
"We" should {
"simulate user input from readline" in {
var outputs = List.empty[String]
def accumulate(output: String): Unit = outputs = outputs :+ output
val in: () => String = () => ":quit"
val out: String => Unit = accumulate _
YourObject.consoleMethod(in, out)
outputs shouldBe List("prompt>", "alibaba.txt: 100%")
}
}
}
In case you want more control you can use scalamock:
In this case we can mock out in and out to behave as we need them to do.
val in = mock[() => String]
val out = mock[String => Unit]
Setting up source expectations:
(in.apply _).expects().anyNumberOfTimes().onCall(_ => ":quit")
Now we want to set up out to record whatever we are going to write:
var outputs = List.empty[String]
def accumulate(output: String): Unit = outputs = outputs :+ output
(out.apply _)
.expects(new FunctionAdapter1[String, Boolean](_ => true))
.anyNumberOfTimes()
.onCall(accumulate _)
Perfect, now let's set up the expectations:
outputs shouldBe List("prompt>", "alibaba.txt: 100%")
Full source code of the test:
import org.scalamock.function.FunctionAdapter1
import org.scalamock.scalatest.MockFactory
import org.scalatest.{Matchers, WordSpec}
class Test extends WordSpec with Matchers with MockFactory {
"We" should {
"simulate user input from readline" in {
val in = mock[() => String]
val out = mock[String => Unit]
(in.apply _).expects().anyNumberOfTimes().onCall(_ => ":quit")
var outputs = List.empty[String]
def accumulate(output: String): Unit = outputs = outputs :+ output
(out.apply _)
.expects(new FunctionAdapter1[String, Boolean](_ => true))
.anyNumberOfTimes()
.onCall(accumulate _)
YourObject.consoleMethod(in, out)
outputs shouldBe List("prompt>", "alibaba.txt: 100%")
}
}
}
Related
I am new to the Spock framework and writing a test case in which I am trying to Mock a class called QueryDatabase
public class QueryDatabase {
public BigInteger countRecords(Instant start, Instant end) {
Flux<CountRecord> countValue = query("select * from users");
Optional<Object> value = Optional.ofNullable(countValue.blockFirst()).map(CountRecord::getValue);
BigInteger count = value.filter(BigInteger.class::isInstance)
.map(BigInteger.class::cast).orElse(BigInteger.valueOf(0));
return count
}
public Flux<CountRecord> query(String query) {
}
}
but the below test case which is to check the value returned by countRecords(Instant, Instant) always gives 0, so that means the value returned in the when section
recordCount.query(_) >> Flux.just(CountRecord.builder().value(new BigInteger(133)).build())
is not getting used, seems like recordCount.query(_) >> Flux.empty() also does not have any impact and it always returns the default BigInteger value 0
def "record count"() {
given:
def now = Instant.now()
def last10Minutes = now.minus(10, ChronoUnit.MINUTES);
def recordCount = Stub(QueryDatabase)
when: "query returning empty flux"
recordCount.query(_) >> Flux.empty()
then:
recordCount.countRecords(last10Minutes, now) == 0
when: "query returning the count record"
recordCount.query(_) >> Flux.just(CountRecord.builder().value(new BigInteger(133)).build())
then:
recordCount.countRecords(last10Minutes, now) == 133
}
Am I doing anything wrong here?
There are several issues with your code.
You try to set up some stubbing in the when block
You perform your action in the then block
You try to redefine stubs
See Combining Mocking and Stubbing on how this works.
def "record count"() {
given:
def now = Instant.now()
def last10Minutes = now.minus(10, ChronoUnit.MINUTES);
def recordCount = Spy(QueryDatabase)
when: "query returning empty flux"
def result = recordCount.countRecords(last10Minutes, now)
then:
1 * recordCount.query(_) >> Flux.empty()
result == 0
when: "query returning the count record"
def 2ndResult = recordCount.countRecords(last10Minutes, now) == 133
then:
1 * recordCount.query(_) >> Flux.just(CountRecord.builder().value(new BigInteger(133)).build())
2ndResult == 133
}
Alternatively, you could split it up into a data driven feature
def "record count"(BigInteger result, Flux input) {
given:
def now = Instant.now()
def last10Minutes = now.minus(10, ChronoUnit.MINUTES);
def recordCount = Spy(QueryDatabase)
recordCount.query(_) >> input
expect:
recordCount.countRecords(last10Minutes, now) == result
where:
result | input
0 | Flux.empty()
133 | Flux.just(CountRecord.builder().value(new BigInteger(133)).build())
}
Normally, you'd order the parameters the other way around, but since the fluxes are so verbose I find this better readable.
--
EDIT:
I missed that you are trying to stub that same object that you are testing, this can only be done with partial mocking and often indicates, that the code should be refactored. So replace Mock/Stub with Spy for partial mocking.
What about this way when you override the query method to return an expected Flux. In this case I would recommend to have 2 tests:
def "record count when empty Flux"() {
given:
def now = Instant.now()
def last10Minutes = now.minus(10, ChronoUnit.MINUTES);
def recordCount = new QueryDatabase() {
#Overriden
public Flux<CountRecord> query(String query) {
Flux.empty()
}
}
expect:
recordCount.countRecords(last10Minutes, now) == 0
}
def "record count when non empty Flux"() {
given:
def now = Instant.now()
def last10Minutes = now.minus(10, ChronoUnit.MINUTES);
def recordCount = new QueryDatabase() {
#Overriden
public Flux<CountRecord> query(String query) {
Flux.just(CountRecord.builder().value(new BigInteger(133)).build())
}
}
expect:
recordCount.countRecords(last10Minutes, now) == 133
}
Screen capture of Result tree
Code keeps running in infinite loop , wheather the data matches or not.
Also i want to ignore the first/header column when comparing. Can you
please help with this.
Thanks
I am using below code to compare 2 csv files.
Input Files:
File1
ColumnA
A
B
C
File2
ColumnA
A
B
D
Code
#import java.io.File;#
#import java.io.FileReader;#
#import java.io.LineNumberReader;#
String strfile1 = vars.get("thisScriptPath") + "file1.csv";
String strfile2 = vars.get("thisScriptPath") + "file2.csv";
def file1 = new File('/path/to/file1')
def file2 = new File('/path/to/file2')
def file1Lines = file1.readLines('UTF-8')
def file2Lines = file2.readLines('UTF-8')
if (file1Lines.size() != file2Lines.size()) {
SampleResult.setSussessful(false)
SampleResult.setResponseMessage('Files size is different, omitting line-by-line compare')
} else {
def differences = new StringBuilder()
file1Lines.eachWithIndex { String file1Line, int number ->
String file2Line = file2Lines.get(number)
if (!file1Line.equals(file2Line)) {
differences.append('Difference # ').append(number).append('. Expected: ').append(file1Line).append('. Actual: ' + file2Line)
differences.append(System.getProperty('line.separator'))
}
}
if (differences.toString().length() > 0) {
SampleResult.setSuccessful(false)
SampleResult.setResponseMessage(differences.toString())
}
}
REFER IMAGE
I am trying to introduce a method in my program which should result into a substring. I wrote the following code but why would not this work?
class testmethod {
String FQDN = "TEST.domain.local"
def sname = shortname(FQDN);
println $sname
def shortname(Longname)
{
shortname1 = Longname.substring(0, Longname.indexOf('.'))
return shortname1
}
}
First of all the code should be(for better readability) :-
def shortname(String Longname) not def shortname(Longname).
Also shortname1 = Longname.substring(0, Longname.indexOf('.')) in this shortname1 is not defined.
Moreover you can try :-
def shortname(String Longname)
{
String[] shortnameArr = Longname.split("\\.");
return shortnameArr[0];// will return TEST
}
You're mixing both script and class concepts of the Groovy in one single piece of code.
Just remove the class definition and $ sign to use the script way:
String FQDN = "TEST.domain.local"
def sname = shortname(FQDN);
println sname
def shortname(Longname)
{
shortname1 = Longname.substring(0, Longname.indexOf('.'))
return shortname1
}
Or add class initialization and local variable declaration to use the class way:
class testmethod {
String FQDN = "TEST.domain.local"
def sname = shortname(FQDN);
def shortname(Longname)
{
def shortname1 = Longname.substring(0, Longname.indexOf('.'))
return shortname1
}
}
def tc = new testmethod()
println tc.sname
Have Seq[Byte] in scala . How to convert it to java byte[] or Input Stream ?
wouldn't
val a: Seq[Byte] = List()
a.toArray
do the job?
You can copy the contents of a Seq With copyToArray.
val myseq: Seq[Byte] = ???
val myarray = new Array[Byte](myseq.size)
myseq.copyToArray(myarray)
Note that this will iterate through the Seq twice, which may be undesirable, impossible, or just fine, depending on your use.
A sensible option:
val byteSeq: Seq[Byte] = ???
val byteArray: Array[Byte] = bSeq.toArray
val inputStream = java.io.ByteArrayInputStream(byteArray)
A less sensible option:
object HelloWorld {
implicit class ByteSequenceInputStream(val byteSeq: Seq[Byte]) extends java.io.InputStream {
private var pos = 0
val size = byteSeq.size
override def read(): Int = pos match {
case `size` => -1 // backticks match against the value in the variable
case _ => {
val result = byteSeq(pos).toInt
pos = pos + 1
result
}
}
}
val testByteSeq: Seq[Byte] = List(1, 2, 3, 4, 5).map(_.toByte)
def testConversion(in: java.io.InputStream): Unit = {
var done = false
while (! done) {
val result = in.read()
println(result)
done = result == -1
}
}
def main(args: Array[String]): Unit = {
testConversion(testByteSeq)
}
}
I'm writing a small data access library to help me use Cassandra prepared statements in a Scala program (its not open source but maybe one day). What I'd like to do is automatically generate a Java Array for the bind statement from the case class
com.datastax.driver.core
PreparedStatement...
public BoundStatement bind(Object... values);
So currently I have
case class Entity(foo:String, optionalBar:Option[String])
object Entity {
def toJArray(e:Entity) = { Array(e.foo, e.optionalBar.getOrElse(null)) }
}
val e1 = Entity("fred", Option("bill"))
val e2 = Entity("fred", None)
Entity.toJArray(e1)
res5: Array[String] = Array(fred, bill)
Entity.toJArray(e2)
res6: Array[String] = Array(fred, null)
The toJArray returns an Array I can use in the bind statement. The boiler plate code gets worse if there is a date or double or a java enum
new java.util.Date(createdOn)
scala.Double.box(price)
priceType.name
Is there a way of automatically generating the Array in Scala assuming the bind parameters have the same order as the case class fields?
EDIT Thanks to #srgfed01
Here's what I came up with (not complete) but allows me to do something like
val customer1 = Customer( "email", "name", None, Option(new Date), OrdStatus.New)
session.execute(populate(customer1, insert))
val customer2 = Customer( "email2", "name2", Option(22), Option(new Date), OrdStatus.Rejected)
session.execute(populate(customer2, insert))
using this function
def populate(state:Product, statement:PreparedStatement): BoundStatement = {
def set(bnd:BoundStatement, i:Int, aval:Any): Unit = {
aval match {
case v:Date => bnd.setDate(i, v)
case v:Int => bnd.setInt(i, v)
case v:Long => bnd.setLong(i, v)
case v:Double => bnd.setDouble(i, v)
case v:String => bnd.setString(i, v)
case null => bnd.setToNull(i)
case _ => bnd.setString(i, aval.toString)
}
}
val bnd = statement.bind
for(i <- 0 until state.productArity) {
state.productElement(i) match {
case op: Option[_] => set(bnd, i, op.getOrElse(null))
case v => set(bnd, i, v)
}
}
bnd
}
You can use productIterator call for your case class object:
case class Entity(foo: String, optionalBar: Option[String])
val e1 = Entity("fred", Option("bill"))
val e2 = Entity("fred", None)
def run(e: Entity): Array[Any] = e.productIterator
.map {
case op: Option[_] => op.getOrElse(null)
case v => v
}
.toArray
println(run(e1).mkString(" ")) // fred bill
println(run(e2).mkString(" ")) // fred null