Created
July 4, 2019 16:36
-
-
Save iamanandkris/6db329d8638ef278c1bf8db5351d0a2c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scalaz.zio._ | |
type UserID = String | |
case class UserProfile(name: String) | |
//Companion object for below Database Module. | |
object Database { | |
// The database module contains the database service: | |
trait Service { | |
def lookup(id: UserID): Task[UserProfile] | |
def update(id: UserID, profile: UserProfile): Task[Unit] | |
} | |
} | |
// The database module, its like a Free algebra definition | |
trait Database { | |
val database: Database.Service | |
} | |
//Companion for below Logger Module | |
object Logger { | |
// The logger module contains the logger service: | |
trait Service { | |
def info(id: String): Task[Unit] | |
} | |
} | |
// The logger module: | |
trait Logger { | |
def logger: Logger.Service | |
} | |
//Base trait for all the operations that are to be recorded when running test | |
trait Operation | |
//The TestState | |
final case class ExecutedInstructions(ops: List[Operation]) | |
// A concurrent-safe test database service, which uses a `Ref` to keep track | |
// of changes to the instruction set: | |
class DatabaseTestService(ref: Ref[ExecutedInstructions]) extends Database.Service { | |
private var map: Map[UserID, UserProfile] = Map("abc" -> UserProfile("testName")) | |
def lookup(id: UserID): Task[UserProfile] = | |
ref.update(x => x.copy(ops = x.ops :+ DatabaseTestService.UserLookedUp(id))).map(x => map(id)) | |
def update(id: UserID, profile: UserProfile): Task[Unit] = | |
ref.update(x => x.copy(ops = x.ops :+DatabaseTestService.UserUpdated(id, profile))).map(x => map = map + (id -> profile)) | |
} | |
object DatabaseTestService { | |
// database operations performed against the database: | |
trait DatabaseOperation extends Operation | |
case class UserUpdated(id:UserID, profile:UserProfile) extends DatabaseOperation | |
case class UserLookedUp(id:UserID) extends DatabaseOperation | |
} | |
// A concurrent-safe test logger service, which uses a `Ref` to keep track | |
// of changes to the instruction set: | |
class LoggerTestService(ref: Ref[ExecutedInstructions]) extends Logger.Service { | |
def info(line: String): Task[Unit] = | |
ref.update(x => x.copy(ops = x.ops :+ LoggerTestService.MessageLogged(line))).map(x => ()) | |
} | |
object LoggerTestService{ | |
trait LoggerOperation extends Operation | |
case class MessageLogged(message:String) extends LoggerOperation | |
} | |
// A helper function to run a test scenario, and extract out test data. | |
// This function can be used many times across many unit tests. | |
def testScenario[E, A](initialState: ExecutedInstructions) | |
(eff: ZIO[Database with Logger, E, A]): UIO[(Either[E, A], ExecutedInstructions)] = { | |
for { | |
instructionRef <- Ref.make(initialState) | |
// Construct a new environment for the effect being tested: | |
env = new Database with Logger { | |
val database = new DatabaseTestService(instructionRef) | |
val logger = new LoggerTestService(instructionRef) | |
} | |
either <- eff.provide(env).either | |
instructionState <- instructionRef.get | |
} yield (either, instructionState) | |
} | |
// An example program that uses database and logger modules. This is the actual business logic to execute: | |
val lookedUpProfile: ZIO[Database with Logger, Throwable, UserProfile] = | |
ZIO.accessM[Logger with Database] { modules => | |
import modules.database | |
import modules.logger | |
for { | |
profile <- database.lookup("abc") | |
_ <- logger.info(profile.name) | |
} yield profile | |
} | |
// Running a test scenario and unsafely executing it to see what happens: | |
val v = testScenario(ExecutedInstructions(Nil))(lookedUpProfile) | |
val runtime = new DefaultRuntime {} | |
runtime.unsafeRun(v) //Result - (Right(UserProfile(testName)),ExecutedInstructions(List(UserLookedUp(abc), MessageLogged(testName)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment