Search code examples
scalaunit-testingscalatest

Unit Testing IO 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"))
  }

Solution

  • 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.