Some time ago I wrote a proof-of-concept implementation of a miniature event sourced system in Clojure. I used spec to lay out my events and commands and then used that to generate tests. That is, I wrote some test functions applying the given/when/then pattern where given was a sequence of events and when was a command and the required data were automagically generated by spec.test. Worked like a charm, except for the part where I thought using monads was a good idea. Oh, well.
I wish that you had included testing on the read side. Transforming a command into an event is generally the easier process. Proving that your events generate snapshots and hydrate correctly feels more important.
The tests themselves prove that the hydration of the aggregate is occurring otherwise the commands would fail and you wouldn't be emitting the event. As for snapshots, I've done a video about them,, which I think generally you should try and avoid them (if you can). Testing ultimately would be very similar to what's in this video. Provide a snapshot as the aggregate, then test behaviors. As for projections (read side), that's another topic entirely :)
@@CodeOpinion Thank you for the response, I definitely was looking at this through the lens of implementations I've used in the past and generally I don't hydrate on write but that is a good point. I think my original point was more from the direction of querying the service for the information but I can see how with hydration tested this just becomes a wiring problem.
Hey! Thanks for your video. I'm actually asking myself how I could test the internal state of my aggregate after having received a command method. When you do not use event sourcing, you assert your mutating properties by calling getters "AssertEquals(5, aggregate.GetValue())" or you build the whole expected objet and test it against the mutated one "AssertEquals(expected, actualAggregate)". With event sourcing, you are testing that specific events have been created and I totally agree with that way. But how do you test that applying those generated events, have been successful? (Let's say you receive a command method which raises an event but source code for applying that event is bugged or partial. Your test is green because you only have tested that a kind of event with expected data has been generated.) I've found several solutions around that: - query all my aggregate properties which are supposed to mutate and assert those with the expected values (but that may involves to expose unnecessary getters) - load my aggregate from its repository and assert it against a built expected aggregate (that does not work because it will applies events and execute the non working code and leads to a false positive test) - query the read model and assert it against a built expected read model (that could work but I would not recommend that) To make a quick summary of my question, how do you internally assert the whole aggregate after a mutation in addition to testing generated events? Thanks!
In addition to my question, I know what you can do acceptance testing or assert into the database (integration testing) but I wanted to find a solution for a in memory unit test without exposing the internal state of my aggregate with getters. Also, I don't only rely on in memory unit test of course. Also I don't want to assert the inserted row inside of my aggregate event store table.
The internal state (projection) is only useful for the behavior your testing. In other words the setup is doing that. In non-event sourced aggregates, the side effects (state changes( to the underlying data model can be asserted if you pass the data model into the aggregate root when constructing.
It's just a list of events that have been added via the aggregate. Generally you'll use it so a repository something else can get the events that need to be persisted to your event store.
@@CodeOpinion Thanks for the response! So you have two distinct lists? One for not persisted and other for persisted or just one list? I mean if you after you fetch the aggregate by some repository and you add new events to it how can you get the not persisted? Maybe id = null? thanks
I think in this example I had AddEvent and ApplyEvent has two separate things. So in this case, you don't need all the list of already persisted events, since you're just applying them to the aggregate. AddEvent will Apply then add it to the list of uncommited events.
What type of data store are you using to be able to replay events all the time without performance penalties? If I was to use this with Azure Cosmos DB as the event store, the constant lookup and replay of events would increase the RU which in turn would cost more money or cause rate limiting. A way around it could possibly be with materialized views from the change feed, but that's not really and aggregate. So I'm very confused after watching multiple videos. If you're using CQRS+ES and you send a command request via HTTP, are you not breaking convention by querying the data in the command?
If events are persisted in order and applied in order you won't break an a invariant because you're not applying them when rebuilding state. You're only checking invariants BEFORE you create an event. An event is the result and confirmation of a command.
Unfortunately I don't think it's available in all countries. support.google.com/youtube/answer/6307365?hl=en#zippy=%2Cpremium-memberships-available-locations
Event sourcing seems quite.... niche? I am not sure how mainstream it is becoming. Is EventSourcing going to become more and more prevelant as he de-facto method of data-storage do you think? I would really like to see a video where you go entirely from scratch, from talking to a fake customer/client one by one, doing event storming and showing the code changes along the way moving gradually into a more and more complete App. (unrelated but could include eventsource I suppose) There are hundreds of "heres the final product" videos/articles/repo's out there, but almost none that show the development of an app using full DDD, with the most important point: HOW those decisions were made at the client/discovery level Thanks for the awesome videos as always!
It's doesn't think event sourcing has widespread adoption. I think it's more misunderstood than anything. The course I'm currently working on hopefully it's some of what you're mentioning.
@@CodeOpinion Ive read/watched learned SO much the last few months, and I'm realizing what I've been missing all along is a mentor/team/company to hold my hand and give me confidence with all the concepts put into practice. This is true in almost everything I think, you learn about it but don't really have full confidence unless you see experts doing it.
This tutorial is very useful, however I am a member of this channel and I need the source code of this tutorial, but I can't find it anyway in the perks.
I'd add that when testing an event sourced system (really any type of system) that nothing should hit the hard disk. Use an in-memory event queue / database if at all possible. Otherwise your tests can be painfully slow.
Hmmm I wouldn't say "nothing". You're implying that you want tests to be fast and that "real" infrastructure will be slow. That's not always the case. There are many situations where you absolutely need to hit the "real" DB if you're leveraging DB specifics (concurrency/locking comes to mind). While I agree with the sentiment, "nothing" is a bit of a line I don't agree with.
I just found your channel for a day and I've been watching a lot of your videos. You are my new favorite Programming Channel right now🚀
Thanks. I appreciate that!
Some time ago I wrote a proof-of-concept implementation of a miniature event sourced system in Clojure. I used spec to lay out my events and commands and then used that to generate tests. That is, I wrote some test functions applying the given/when/then pattern where given was a sequence of events and when was a command and the required data were automagically generated by spec.test. Worked like a charm, except for the part where I thought using monads was a good idea. Oh, well.
Very Interesting!
Why did I not find this channel earlier!! Great video. It'd be awesome if you covered Event Storming.
Great suggestion!
I wish that you had included testing on the read side. Transforming a command into an event is generally the easier process. Proving that your events generate snapshots and hydrate correctly feels more important.
The tests themselves prove that the hydration of the aggregate is occurring otherwise the commands would fail and you wouldn't be emitting the event. As for snapshots, I've done a video about them,, which I think generally you should try and avoid them (if you can). Testing ultimately would be very similar to what's in this video. Provide a snapshot as the aggregate, then test behaviors. As for projections (read side), that's another topic entirely :)
@@CodeOpinion Thank you for the response, I definitely was looking at this through the lens of implementations I've used in the past and generally I don't hydrate on write but that is a good point. I think my original point was more from the direction of querying the service for the information but I can see how with hydration tested this just becomes a wiring problem.
Hey! Thanks for your video.
I'm actually asking myself how I could test the internal state of my aggregate after having received a command method.
When you do not use event sourcing, you assert your mutating properties by calling getters "AssertEquals(5, aggregate.GetValue())" or you build the whole expected objet and test it against the mutated one "AssertEquals(expected, actualAggregate)".
With event sourcing, you are testing that specific events have been created and I totally agree with that way.
But how do you test that applying those generated events, have been successful? (Let's say you receive a command method which raises an event but source code for applying that event is bugged or partial. Your test is green because you only have tested that a kind of event with expected data has been generated.)
I've found several solutions around that:
- query all my aggregate properties which are supposed to mutate and assert those with the expected values (but that may involves to expose unnecessary getters)
- load my aggregate from its repository and assert it against a built expected aggregate (that does not work because it will applies events and execute the non working code and leads to a false positive test)
- query the read model and assert it against a built expected read model (that could work but I would not recommend that)
To make a quick summary of my question, how do you internally assert the whole aggregate after a mutation in addition to testing generated events?
Thanks!
In addition to my question, I know what you can do acceptance testing or assert into the database (integration testing) but I wanted to find a solution for a in memory unit test without exposing the internal state of my aggregate with getters. Also, I don't only rely on in memory unit test of course. Also I don't want to assert the inserted row inside of my aggregate event store table.
The internal state (projection) is only useful for the behavior your testing. In other words the setup is doing that. In non-event sourced aggregates, the side effects (state changes( to the underlying data model can be asserted if you pass the data model into the aggregate root when constructing.
Nice video! How does GetUncommittedEvents method works? thanks!
It's just a list of events that have been added via the aggregate. Generally you'll use it so a repository something else can get the events that need to be persisted to your event store.
@@CodeOpinion Thanks for the response! So you have two distinct lists? One for not persisted and other for persisted or just one list? I mean if you after you fetch the aggregate by some repository and you add new events to it how can you get the not persisted? Maybe id = null? thanks
I think in this example I had AddEvent and ApplyEvent has two separate things. So in this case, you don't need all the list of already persisted events, since you're just applying them to the aggregate. AddEvent will Apply then add it to the list of uncommited events.
Nice look and feel. I'd be interested to see you declare intended behavior with multiple events.
That was actually my plan, which I forgot about! Thats why I created the Given() and Then() to have a param of IEvents.
Awesome I did this when I was learning it yes I agree with you it way easier using the bdd method amazingly so
Good to hear!
What type of data store are you using to be able to replay events all the time without performance penalties?
If I was to use this with Azure Cosmos DB as the event store, the constant lookup and replay of events would increase the RU which in turn would cost more money or cause rate limiting. A way around it could possibly be with materialized views from the change feed, but that's not really and aggregate.
So I'm very confused after watching multiple videos. If you're using CQRS+ES and you send a command request via HTTP, are you not breaking convention by querying the data in the command?
If performance of replaying events is an issue, you can use snapshots. Check out this video: ruclips.net/video/eAIkomEid1Y/видео.html
In an event sourcing ,if events are applied properly, in correct order ,teoretically is possible that an aggregate invariants to be broken?
If events are persisted in order and applied in order you won't break an a invariant because you're not applying them when rebuilding state. You're only checking invariants BEFORE you create an event. An event is the result and confirmation of a command.
How can I join the channel? I don't have the 'Join' button..
Unfortunately I don't think it's available in all countries. support.google.com/youtube/answer/6307365?hl=en#zippy=%2Cpremium-memberships-available-locations
@@CodeOpinion Oh, so looks like I should have the premium account. Thank you
Event sourcing seems quite.... niche? I am not sure how mainstream it is becoming. Is EventSourcing going to become more and more prevelant as he de-facto method of data-storage do you think?
I would really like to see a video where you go entirely from scratch, from talking to a fake customer/client one by one, doing event storming and showing the code changes along the way moving gradually into a more and more complete App. (unrelated but could include eventsource I suppose)
There are hundreds of "heres the final product" videos/articles/repo's out there, but almost none that show the development of an app using full DDD, with the most important point: HOW those decisions were made at the client/discovery level
Thanks for the awesome videos as always!
It's doesn't think event sourcing has widespread adoption. I think it's more misunderstood than anything. The course I'm currently working on hopefully it's some of what you're mentioning.
@@CodeOpinion Ive read/watched learned SO much the last few months, and I'm realizing what I've been missing all along is a mentor/team/company to hold my hand and give me confidence with all the concepts put into practice. This is true in almost everything I think, you learn about it but don't really have full confidence unless you see experts doing it.
how can I have the source code of the toturial ?
Developer level members of my RUclips channel get access.
ruclips.net/channel/UC3RKA4vunFAfrfxiJhPEplwjoin
www.patreon.com/codeopinion
Thanks for the great video!
Glad you liked it!
This tutorial is very useful, however I am a member of this channel and I need the source code of this tutorial, but I can't find it anyway in the perks.
Go to the community tab, you will see links within the posts that are only visible to members.
Nice one
I'd add that when testing an event sourced system (really any type of system) that nothing should hit the hard disk. Use an in-memory event queue / database if at all possible. Otherwise your tests can be painfully slow.
Hmmm I wouldn't say "nothing". You're implying that you want tests to be fast and that "real" infrastructure will be slow. That's not always the case. There are many situations where you absolutely need to hit the "real" DB if you're leveraging DB specifics (concurrency/locking comes to mind). While I agree with the sentiment, "nothing" is a bit of a line I don't agree with.
@@CodeOpinion You're right, one should avoid the extremes.
👏👏👏