meteor-space / event-sourcing

CQRS and Event Sourcing Infrastructure for Meteor.
MIT License
63 stars 9 forks source link

Testing application based on commands and events #2

Closed rhyslbw closed 9 years ago

rhyslbw commented 9 years ago

Do you create tests within your application that are similar to the integration test in this package to serve as a lower level testing suite for the domain models? ie testing command handling and event publishing using practicalmeteor:munit and space:testing rather than the typical internal unit tests?

I know this is one of the benefits of using this type of architecture, and sounds like it makes a great combination with cucumber for acceptance testing/BDD, but just wanted to get your perspective.

rhyslbw commented 9 years ago

Ah I see munit is designed to test packages, and space:testing just provides helpers for the space components right? Maybe my question should be, do you package all your domain logic and then use meteor test-packages, or are you using another package like sanjo:jasmine in combination with space:testing for application testing within Velocity?

DominikGuzei commented 9 years ago

Hey @rhyslbw! I use several techniques for testing, each one has its benefits and downsides:

  1. Unit tests: one class, testing all the methods and very detailed behavior. a good example would be to test how an aggregate reacts to method calls and events. Another good case for strong unit tests are value objects (one of my favorite patterns from DDD).
  2. Integration Tests: Build a simple scenario where multiple components work together (send/receive messages) and only test the bigger outcome, like what gets written into the db.
  3. Acceptance Tests: High-Level end-to-end tests from user perspective based on user-stories. These are very important, because they are the only tests that really ensure that your complete product is working correctly. But they are extremely slow compared to the others. So you cannot cover every little aspect of business logic with these tests. Another problem is that these tests won't directly show you where a problem lies in your code because they are so high-level.

I use practicalmeteor:munit + the helpers from space:testing for all my unit and integration tests and space:pioneer for acceptance testing. However I consider switching to meteor-cucumber for end-to-end tests and will merge my efforts with sam there :wink:

This implies that you write all of your tested code in packages (which I do) so you can use meteor test-packages ./ to run all your tests or meteor test-packages packages/my-package to run only specific tests

rhyslbw commented 9 years ago

Thanks for the detailed insight as usual @DominikGuzei. I watched one of Greg Young's CQRS and Event Sourcing classes, and the point about testing based on commands and events without worrying too much about the minute detail makes the landscape a lot flatter, although I can see there are specific areas where this detail is required.

I'm going to go with the packaged approach as defining the load order is more important than the time spent wiring up the package.js. Do you just have one package for your domain model in the bounded context and then application services packaged by feature?

I think your choice to switch to xolvio:cucumber will be a good move as there is development underway in Velocity to support the running of tests in parallel which addresses the biggest issue with acceptance testing.

DominikGuzei commented 9 years ago

You're welcome :wink: Yeah, the biggest benefit or runtime-checked messaging and decoupling is that you can test your classes mostly from the perspective of input / output. Although I find it quite hard to avoid "real" dependencies in domain objects, so sometimes you also have to inject something and do classic unit testing with mocks, stubs etc.

I started with one big Meteor app and refactored to packages (not even finished yet) because I hated it that I couldn't structure my code the way I wanted without having load-order issues. Luckily setting up a package is very simple in Meteor, so there is not much overhead. And as Greg Young says: "if you worry about the time having to define all your events explicitly, then you probably should not do CQRS+DDD because it seems you are just rushing it." same applies to packages :wink:

What I also love about packages is the possibility to clearly define your bounded contexts. Each package is a separate context of my application with (possibly) many features inside. So I have packages like accounts, licenses, customers, payments which talk with each other only via events and commands

You're right, when I started development 1 year ago, velocity was not really an option. But its much more stable and polished now, so I will give it another chance :wink:

rhyslbw commented 9 years ago

Another benefit of packaging by context is that the codebase is grouped logically for a distributed architecture, although I know at this point it is out of scope.

rhyslbw commented 9 years ago

Are accounts, licenses, customers, payments Space.Modules?

Do you have a global namespace that represents your application such as Prisma defined in a base package then modules like Prisma.accounts Prisma.licenses etc with the Space.Application extension as Prisma.app?

If so, do you put commands and event definitions in this base package, eg Prisma.app.renewSubscription ? (a theoretical command to trigger a feature in the licenses module).

DominikGuzei commented 9 years ago

Yeah exactly, the different bounded contexts (meteor packages) are Space.Modules. Prisma is the base namespace for all app-specific bounded contexts. So I have Prisma.accounts and Prisma.licenses but also Stripe which does not "know" that is used by Prisma and could be extracted and re-used as external package later on.

Currently I have no dedicated app namespace but just have commands and events like Prisma.RenewSubscription or Prisma.CustomerBillingInformationChanged

In general I am still not sure if I like it more to be Prisma.accounts.RegistrationController or just Prisma.AccountsRegistrationController. It's a small difference but honestly I tend to mix both, which might not be a good idea :wink:

rhyslbw commented 9 years ago

Defining events and commands under the base namespace models the concepts well, I'll adopt that. I prefer Prisma.accounts.RegistrationController over Prisma.AccountsRegistrationController as it reinstates the bounded context, and makes the actual names cleaner.

This is also a small point, but if your not defining your Space.Application as Prisma.appis it just a global variable, such asApp`?

DominikGuzei commented 9 years ago

currently the app instance is just a global variable named prisma. But I like your Prisma.app idea better, so I might refactor this :wink: one global less. But I wouldn't use it as namespace for things like events and commands.

rhyslbw commented 9 years ago

This is a good way to explain the intent of the Space.Module and Space.Application components, and how the application is separate from the domain models. It's very expressive particularly if you have multiple apps using the namespace Prisma.WebApp and Prisma.CordovaApp as an example

Do you have any thoughts on building out the documentation, maybe in the wiki? I'd be happy to help

DominikGuzei commented 9 years ago

Hey @rhyslbw, yeah I would love to work on better documentation but rarely find the spare time to do so :wink: would be glad if you want to help, its probably also good to start from an external perspective and I can answer questions and add details where necessary!

rhyslbw commented 9 years ago

Good idea. Maybe we can start by summarising the existing discussion into a few pages in the wiki, then build on any new discoveries of best use. The namespacing current best practice actually is a great start imo as it provides that reiteration on 'where' you are in the domain when coding

DominikGuzei commented 9 years ago

Yeah, i guess it would be good to give a high-level introduction and then provide chapters like Packages & Namespacing, Modules, Messaging, Testing etc.

DominikGuzei commented 9 years ago

Another question is, if we should cover the basics here in this package. Because actually most of the stuff is space:base and space:messaging related …

rhyslbw commented 9 years ago

Yes that was my thought too. Considering messaging is just the infrastructure, I'd suggest the base package for top level docs, then dive into more detail in relevant package repos