-
Couldn't load subscription status.
- Fork 1.4k
ZIO Mock support for impure methods, ZStream and ZSink #3247
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Updated |
|
As soon as CI finishes this is ready to be reviewed & merged @adamgfraser . |
|
@adamgfraser can we rerun https://app.circleci.com/pipelines/github/zio/zio/6519/workflows/3cf22b04-08a3-4c31-9752-bb78704e3270/jobs/67033 ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple of questions and comments but ready to go whenever you are.
| ## Creating a mock service | ||
|
|
||
| We'll be assuming you've read [How to use modules and layers][doc-use-modules-and-layers] guide. In the main sources we define the _service_, a module alias and _capability accessors_. In test sources we're defining the _mock object_ which will hold _capability tags_ and mock layer machinery. | ||
| We'll be assuming you've read [How to use modules and layers][doc-use-modules-and-layers] guide. In the main sources we define the _service_, a module alias and _capability accessors_. In test sources we're defining the _mock object_ which extends `zio.test.mock.Mock` which holds _capability tags_ and _compose layer_. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great that we have a clear separation between source and test now!
| def overloaded(arg1: Long) = invoke(Overloaded._1, arg1) | ||
| val compose: URLayer[Has[Proxy], Example] = | ||
| ZLayer.fromServiceM { proxy => | ||
| withRuntime.map { rts => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe say something about what this is so people don't just think they can do ZIO.runtime[R]?
| def overloaded(arg1: Int) = proxy(Overloaded._0, arg1) | ||
| def overloaded(arg1: Long) = proxy(Overloaded._1, arg1) | ||
| def function(arg1: Int) = rts.unsafeRunTask(proxy(Function, arg1)) | ||
| def sink(a: Int) = rts.unsafeRun(proxy(Sink, a).catchAll(error => UIO(ZSink.fail(error)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to unsafely run a sink or a stream?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The internal mock machinery returns an IO[E, A] where A <: ZStream or A <: ZSink.
For ZStream E = Nothing, becouse any errors happening in creation of the stream are deferred to the first take (moved into streams error channel ZStream[_, E, _]). For ZSink any errors happening upon creation are caught immidietly resulting in a failed Sink, so we need to manually move the error from our internal mock IO[E, _] to a failed ZSink.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we do something like io.foldCauseM(e => ZStream.fail(e), stream)? Maybe I'm not understanding.
| - `E` is the type of error it can fail with | ||
| - `A` is the type of return value it can produce | ||
|
|
||
| The `Capability` type is not publicly available, instead you have to extend `Mock` dependent types `Effect`, `Method`, `Sink` or `Stream`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any other types we want to support mocking? ZManaged? ZSTM? Any way to abstract over this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we should have all ZIO data types covered. I don't see a clean way to abstract over this ATM, but will definately think about it in future.
| */ | ||
| abstract class Method[R <: Has[_]: Tagged, I: Tagged, E: Tagged, A: Tagged](val compose: URLayer[Has[Proxy], R]) | ||
| extends Method.Base[R] { self => | ||
| protected[mock] abstract class Capability[R <: Has[_]: Tagged, I: Tagged, E: Tagged, A: Tagged](val mock: Mock[R]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add variance here or no because of the tags?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't. Variance will break things.
| /** | ||
| * A `Mock[R]` represents a mockable environenment `R`. | ||
| */ | ||
| abstract class Mock[R <: Has[_]: Tagged] { self => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Covariant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would probably break things, but have not tested. I don't think it would bring any value though, at least in current implementation.
Fixes #2734
This PR introduces support for ZStream/ZSink and non-ZIO methods (regular functions/vals) as well as many refactorings/renames as the additional use cases crystalized the design to be more clean.
To be completed it still needs:
@mockablemacro@accessiblemacroadd test coverage for more advanced use cases composing Streams with Effectsadd more advanced examples of mocks composing Streams with Effects@adamgfraser @jdegoes Once these are completed I'd say ZIO Mock is
1.0ready. I'll try to complete these as soon as possible. Opening the PR earlier so you can track progress and review the approach.Out of the scope of this PR is support for polymorphic ZStreams/ZSinks. It will be tricky to get right, so I'll tackle it seperately and would not like it to be a blocker for this PR.