ChatGPT says this should work, but looks like it is mistaken :/
trait Foo { def s: String }
case object A extends Foo { def s = "A" }
case object B extends Foo { def s = "B" }
test("Replace a service in ZIO") {
val layer = ZLayer.succeed[Foo](A)
val otherLayer = ZLayer.succeed[Foo](B)
val app = (for {
foo <- ZIO.service[Foo]
bar <- ZIO.service[String]
} yield foo.s + bar).provide(layer, ZLayer.succeed("foo"))
val otherApp = app.provideSomeLayer(otherLayer)
otherApp.map { s => assertTrue(s == "Bfoo") }
}
I have an app
here that has service A and string "foo". Trying to create the otherApp
from it, replacing A with B, and keeping the rest ("foo") as is.
But no luck - this test fails because the resulting value is still "Afoo" rather than "Bfoo".
What am I doing wrong?
Also (on a sort of different topic), if I change provide
there to
provideLayer(layer).provide(ZLayer.succeed("foo")
, it no longer compiles saying it wants layer
to be Foo with String
. Is there no way to provide some dependencies to the effect, and leave others undefined?
And one more noob question, while I have your attention. At which point do these ZIOs actually run? Does this test run them both? Or will it only run the otherApp
because it is the only one that is used to produce the return value?
I don't think you can "replace" a layer once it's been provided.
I'm actually even surprised that your usage of
provideSomeLayer
doesn't raise an error because you provided too much layers. Usually it fails to compile when a unnecessary layer is provided.Yes,
provideSome
will do it:If you were outside a ZIO test, nothing would run until you give the
ZIO
to a "runtime" with something like this:But in a ZIO test context, the framework runs the effects for you. So you don't need this "runtime" thing. And I assume that it only runs the effect of the returned value.