Unit Testing IO Scala - scala

I'm starting unit testing in scala using scalatest.
the method I'm testing is as follows :
def readAlpha: IO[Float] = IO {
val alpha = scala.io.StdIn.readFloat()
alpha
}
The test consists of limiting the float that the user inserts to two decimals
Here is what I've tried but that doesn't seem to work.
How could I be fixing it
"alpha" should " have two decimal numbers after comma" in {
val alpha = readAlpha
//assert(alpha == (f"$alpha%.2f"))
}

I cannot say that you are doing wrong, but you cannot compare effect type with a pure type. And It's not possible to write a direct test for the console input app. First of you should mock the readAlpha method somehow, then you should evaluate the value and after that, it's possible to compare them. Here is a small demonstration:
import cats.effect.IO
class ConsoleIO {
def readAlpha: IO[Float] = IO {
val alpha = scala.io.StdIn.readFloat()
alpha
}
}
// ---------------------------------
import cats.effect.{ContextShift, IO, Timer}
import org.scalatest.funsuite.AsyncFunSuite
import scala.concurrent.ExecutionContext
class ConsoleIOTest extends AsyncFunSuite {
class MockConsole extends ConsoleIO {
override def readAlpha: IO[Float] = IO.pure(2.23f)
}
implicit val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global)
implicit val timer: Timer[IO] = IO.timer(ExecutionContext.global)
test("alpha should have two decimal numbers after comma") {
val consoleIO = new MockConsole
val alpha = consoleIO.readAlpha.unsafeRunSync()
assert(alpha.toString === (f"$alpha%.2f"))
}
}
Here unsafeRunSync() produces the result by running the encapsulated effects as impure.

Related

mocking method inside another method scala

I am having a problem while mocking a method that is being called in another method.
For example: Below in my main class.
class Trial extends TrialTrait {
def run(): String ={
val a = createA()
val b = a.split(" ")
val c = b.size
val d = c + " words are there"
d
}
def createA(): String = {
var a = "above all the things that have been done, one thing remained in silent above all the things that have been done one thing remained in silent above all the that "
a
}
}
Below is my mock code.
class TryMock4 extends FunSuite with BeforeAndAfterEach with MockFactory {
val trial = new Trial
val st = stub[TrialTrait]
test("Mocking the DataFrame") {
val input = "above all the things that have been done, one thing remained in silent above "
(st.createA _).when().returns(input)
val expected = "14 words are there"
val actual = st.run()
Assert.assertEquals(expected,actual)
}
}
What I am trying to do is, passing mocking data to createA and use that in the run method.
But, it is giving null value after running the run method.
Could you please suggest how it can be achieved?
I don't think you need a mock in this case, just a regular override should suffice.
class TrialTest extends FlatSpec with Matchers {
behavior of "Trial"
it should "count words" in {
val input = "above all the things that have been done, one thing remained in silent above "
val trial = new Trial {
override def createA(): String = input
}
val expected = "14 words are there"
val actual = trial.run()
actual should be (expected)
}
}
However, should you really want to use a mock here, it's possible with scalamock.
You can define our own class that makes part of the class final (the bit you don't want to mock), see below:
class TrialTestWithMock extends FlatSpec with Matchers with MockFactory {
behavior of "Trial"
it should "count words" in {
val input = "above all the things that have been done, one thing remained in silent above "
class FinalTrial extends Trial {
final override def run(): String = super.run()
}
val trial = mock[FinalTrial]
(trial.createA _).expects().returning(input).anyNumberOfTimes()
val expected = "14 words are there"
val actual = trial.run()
actual should be (expected)
}
}

Scala: Invokation of methods with/without () with overridable implicits

Here is a definition of method, that uses ExecutionContext implicitly, and allows client to override it. Two execution contexts are used to test it:
val defaultEc = ExecutionContext.fromExecutor(
Executors.newFixedThreadPool(5))
Names of threads look like: 'pool-1-thread-1' to 'pool-1-thread-5'
And the 2nd one from Scala:
scala.concurrent.ExecutionContext.Implicits.global
Names of threads look like: 'scala-execution-context-global-11'
Client can override default implicit via:
implicit val newEc = scala.concurrent.ExecutionContext.Implicits.global
Unfortunately it is overridable only, when a method with implicit is invoked without ():
val r = FutureClient.f("testDefault") //prints scala-execution-context-global-11
not working:
val r = FutureClient.f("testDefault")() //still prints: pool-1-thread-1
The question is WHY it works this way? Cause it makes it much more complicated for clients of API
Here is a full code to run it and play:
object FutureClient {
//thread names will be from 'pool-1-thread-1' to 'pool-1-thread-5'
val defaultEc = ExecutionContext.fromExecutor(
Executors.newFixedThreadPool(5))
def f(beans: String)
(implicit executor:ExecutionContext = defaultEc)
: Future[String] = Future {
println("thread: " + Thread.currentThread().getName)
TimeUnit.SECONDS.sleep(Random.nextInt(3))
s"$beans"
}
}
class FutureTest {
//prints thread: pool-1-thread-1
#Test def testFDefault(): Unit ={
val r = FutureClient.f("testDefault")
while (!r.isCompleted) {
TimeUnit.SECONDS.sleep(2)
}
}
//thread: scala-execution-context-global-11
#Test def testFOverridable(): Unit ={
implicit val newEc = scala.concurrent.ExecutionContext.Implicits.global
val r = FutureClient.f("testDefault")
while (!r.isCompleted) {
TimeUnit.SECONDS.sleep(2)
}
}
//prints pool-1-thread-1, but not 'scala-execution-context-global-11'
//cause the client invokes f with () at the end
#Test def testFOverridableWrong(): Unit ={
implicit val newEc = scala.concurrent.ExecutionContext.Implicits.global
val r = FutureClient.f("testDefault")()
while (!r.isCompleted) {
TimeUnit.SECONDS.sleep(2)
}
}
}
I have already discussed a couple of related topics, but they are related to API definition, so it is a new issue, not covered by those topics.
Scala Patterns To Avoid: Implicit Arguments With Default Values
f("testDefault") (or f("testDefault")(implicitly)) means that implicit argument is taken from implicit context.
f("testDefault")(newEc) means that you specify implicit argument explicitly. If you write f("testDefault")() this means that you specify implicit argument explicitly but since the value isn't provided it should be taken from default value.

First click on button has an odd behaviour

I am working on a todo list app using
scalajs,
cats (free monads), and
scalajs-react
When I am using a simple model like the code below, everything works like expected.
class TodoModel() {
private object State {
var todos = Seq.empty[Todo]
def mod(f: Seq[Todo] => Seq[Todo]): Callback = {
val newTodos = f(todos)
Callback(todos = newTodos)
}
}
def add(t: Todo): Callback = State.mod(_ :+ t)
def todos: Seq[Todo] = State.todos
}
Once I use the free monads from cats, I have an odd behaviour. The first click always inserts two todo entries. Every click afterwards works like expected. See the pictures below.
What is wrong here?
import cats.free.Free
import cats.free.Free.liftF
import japgolly.scalajs.react._
import japgolly.scalajs.react.vdom.html_<^._
import org.scalajs.dom
case class Todo(text: String)
sealed trait TodoModelOp[A]
case class Add(todo: Todo) extends TodoModelOp[Unit]
case class Todos() extends TodoModelOp[Seq[Todo]]
object FreeTodoModelOps {
// type alias for lifted TodoModelOp
type TodoModelOpF[A] = Free[TodoModelOp, A]
def add(Todo: Todo): TodoModelOpF[Unit] = liftF[TodoModelOp, Unit](Add(Todo))
def todos: TodoModelOpF[Seq[Todo]] = liftF[TodoModelOp, Seq[Todo]](Todos())
}
object StateInterpreter {
import cats.arrow.FunctionK
import cats.{ Id, ~> }
val interpet: TodoModelOp ~> Id = new (TodoModelOp ~> Id) {
val todos = scala.collection.mutable.ArrayBuffer.empty[Todo]
def apply[A](fa: TodoModelOp[A]): Id[A] = fa match {
case Add(todo) => todos += todo; ()
case Todos() => todos.toSeq
}
}
}
class TodoModel() {
import cats.instances.list._
import cats.syntax.traverse._
import FreeTodoModelOps._
def add(t: Todo): Callback = {
def program: TodoModelOpF[Unit] = for {
_ <- FreeTodoModelOps.add(t)
} yield ()
Callback(program.foldMap(StateInterpreter.interpet))
}
def todos: Seq[Todo] = {
def program: TodoModelOpF[Seq[Todo]] = for {
n <- FreeTodoModelOps.todos
} yield n
program.foldMap(StateInterpreter.interpet)
}
}
object TodoPage {
case class Props(model: TodoModel)
case class State(todos: Seq[Todo])
class Backend($: BackendScope[Props, State]) {
val t = Todo("a new todo")
def onSubmit(e: ReactEventFromInput) =
e.preventDefaultCB >>
$.modState(s => State(s.todos :+ t)) >>
$.props.flatMap(P => P.model.add(t))
def render(S: State) =
<.div(
<.form(
^.onSubmit ==> onSubmit,
<.button("Add #", S.todos.length + 1)),
<.ul(S.todos.map(t => <.li(t.text)): _*))
}
val component = ScalaComponent.builder[Props]("Todo")
.initialStateFromProps(p => State(p.model.todos))
.renderBackend[Backend]
.build
def apply(model: TodoModel) = component(Props(model))
}
object Test {
val model = new TodoModel()
def main(args: Array[String]): Unit = {
TodoPage.apply(model).renderIntoDOM(dom.document.getElementById("mount-node"))
}
}
empty, no click on button
first click on button
second click on button
In your first snippet there's a bug:
Here you've got a variable todos (inpure) which you're accessing in a pure context:
def mod(f: Seq[Todo] => Seq[Todo]): Callback = {
val newTodos = f(todos)
Callback(todos = newTodos)
Impurity should be in Callback. Even reading a variable outside of a Callback is unsafe, so it should be:
def mod(f: Seq[Todo] => Seq[Todo]): Callback =
Callback(todos = f(todos))
(See scalajs-react's Ref.scala an example of safely working with a variable.)
Secondly, with regards to your larger snippet, scalajs-react is very FP friendly but that's very unconventional way of trying to use it, and has some significant problems:
StateInterpreter.interpet isn't referentially-transparent; there's shared global state underlying that. Fails the FP test. Stops being a lawful natural transformation.
You're tracking two sets of identical state separately: the component state and the state in TodoModel (impure, fails the FP test). Not only is this approach redundant and runs the risk of the two states getting out-of-sync, but it also makes the component less reusable; imagine you decided to draw it twice on the same screen for the same data - they're going to go out of sync. Best to keep the component stateless and pure.
If you're going to transform a free structure into a component effect, it's best to transform it into a state monad, see here for an example.
It's really, really awesome that you're learning about free monads and scalajs-react. FP will make your entire program really, really easy to reason about and prevent confusing surprises in behaviour, but you've got to not cut any corners and make sure that you keep all of your code pure. Any impurity will render the entire stack all the way up to the entrypoint impure and remove those nice dependable FP properties from those layers. I'd suggest making everything as pure as possible using the points above as starting points, and then I think you'll find that the bug just disappears, or at least is very easy to then detect. Cheers

Import implicit values from a companion object but not used

I wrote some code which acquires some implicit values in the companion object like this:
package example.implicits
class Test {
import Test.GetValue
import Test.Implicits._
val intV = getV[Int]
val stringV = getV[String]
private def getV[T](implicit getV: GetValue[T]): T = getV.value
}
object Test {
trait GetValue[T] {
def value: T
}
object Implicits {
implicit val intValue = new GetValue[Int] {
def value = 10
}
implicit val stringValue = new GetValue[String] {
def value = "ten"
}
}
}
This piece of code cannot be compiled and the compiler complains it couldn't find the required implicit values. Note that my environment is
scala 2.11.8 on Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_66
However, if I use these values explicitly, nothing goes wrong:
class Test {
import Test.GetValue
import Test.Implicits._
val intV = getV[Int](intValue)
val stringV = getV[String](stringValue)
private def getV[T](implicit getV: GetValue[T]): T = getV.value
}
Further more, if I declare new implicit values as following:
class Test {
import Test.GetValue
import Test.Implicits._
implicit val intValue1 = intValue
implicit val stringValue1 = stringValue
val intV = getV[Int]
val stringV = getV[String]
private def getV[T](implicit getV: GetValue[T]): T = getV.value
}
errors will be raised because of ambiguous implicit values.
When I swap position of class Test and object Test, everything goes right:
object Test {
trait GetValue[T] {
def value: T
}
object Implicits {
implicit val intValue = new GetValue[Int] {
def value = 10
}
implicit val stringValue = new GetValue[String] {
def value = "ten"
}
}
}
class Test {
import Test.GetValue
import Test.Implicits._
val intV = getV[Int]
val stringV = getV[String]
private def getV[T](implicit getV: GetValue[T]): T = getV.value
}
So why can't scala find implicit values after I've already imported them in the first case?
And why it can do so when I swap their position?
That's because the compiler hasn't infered the type of Test.intValue yet at the time when it resolves the implicits in getV[Int].
Just give Test.intValue and Test.stringValue their type explicitly, and your problem will be solved.
I read somewhere (sorry, can't remember where exactly), that implicit definitions should always be given an explicit type, notably to avoid this kind of behaviour.

Dynamic object method invocation using reflection in scala

I'm looking to create a way to dynamically call logic depending on template id within scala. So template id 1 calls logic a, template id 2 call logic b, etc. The logic will be diverse but will have the same inputs/outputs. Also the number of different template ids will get into the thousands and will not be known ahead of time, so a loose coupling feels the way to go.
I've started looking at reflection to do this using scala 2.11.1 and can statically use reflection when I know the logic to be used ahead of time but have not found the correct way to dynamically use reflection, so for example passing in template id 2 will call logic b.
Below is a cut down example showing how the static version works and the skeleton I have so far for the dynamic version.
package thePackage
import scala.reflect.runtime.{universe => ru}
trait theTrait { def theMethod(x: String): Unit }
// the different logic held in different objects
object object1 extends theTrait {
def theMethod(x: String) = { println("a " + x ) }
}
object object2 extends theTrait {
def theMethod(x: String) = { println("b " + x ) }
}
object object3 extends theTrait {
def theMethod(x: String) = { println("c " + x ) }
}
// run static/dynamic reflection methods
object ReflectionTest {
// "static" invocation calling object1.theMethod
def staticInvocation() = {
val m = ru.runtimeMirror(getClass.getClassLoader)
val im = m.reflect(thePackage.object1)
val method = ru.typeOf[thePackage.object1.type]
.decl(ru.TermName("theMethod")).asMethod
val methodRun = im.reflectMethod(method)
methodRun("test")
}
staticInvocation
// "dynamic" invocation using integer to call different methods
def dynamicInvocation( y: Integer) = {
val m = ru.runtimeMirror(getClass.getClassLoader)
val module = m.staticModule("thePackage.object" + y)
val im = m.reflectModule(module)
// stuck... static approach does not work here
}
dynamicInvocation(1)
dynamicInvocation(2)
dynamicInvocation(3)
}
What needs to be added/changed to the dynamicInvocation method to make this work, or should I be using a different approach?
You need to get an instance mirror for your module, on which you can reflect the method.
def dynamicInvocation( y: Integer) = {
val m = ru.runtimeMirror(getClass.getClassLoader)
val module = m.staticModule("thePackage.object" + y)
val im = m.reflectModule(module)
val method = im.symbol.info.decl(ru.TermName("theMethod")).asMethod
val objMirror = m.reflect(im.instance)
objMirror.reflectMethod(method)("test")
}
It seems that TermName method in above solution has been replaced by newTermName and also the info.decl seems to not work. Below line worked for me
val method = im.symbol.typeSignature.member(ru.newTermName("testMethod")).asMethod