Search code examples
unit-testingdomain-driven-designcqrsaccessor

Unit Testing Domain Models attributes in CQRS System


I'm seeking other's thoughts on a specific scenario re: unit testing domain model (entities, VOs etc) attributes in a App that is utilising CQRS.

Imagine a simplified example of a Product (entity), with a Product Name (VO).

class Product
private ProductName productName

Product has some basic guard rails and invariants:

  • A Product Name can't be more than 100 characters (enforced in the VO).
  • A Product must have a Product Name (enforced in the entity, with Product Name set in the constructor to ensure it's always valid).

I can unit test the Product entity and Product Name VO to ensure these are enforced correctly by ensuring the correct errors and exceptions are raised. Easy.

My question is regarding Unit Testing the happy path — that the Product Name is set successfully when a Product is initially Developed.

In a non-CQRS system I would have a public read-only property or getter on the Product Name, so that it can be retrieved for reporting, displaying or populating a DTO. I can then unit test with this property.

In a CQRS system though, the Product Name can be private in the Entity, as retrieval of the Product Name happens via the Read Model on the query side. Setting the Product Name happens through the command when the product is Developed, but after that the Product Name isn't required for any core business actions (except I could imagine for renaming the product).

To unit test the successful creation of a product though I need to make the Product Name a read-only public property to test it, but it doesn't seem right to do this just to fulfil a unit test. Without the unit test the Product Name can remain private and everything would work as needed.

Wondering if anyone has come across a similar scenario for unit testing -> Where an attribute that is mostly for presentation purposes (although obviously very important... I wouldn't expect users to try and work with Products via only part numbers or identifiers) is being tested?

I'm leaning towards testing this via the Read Model? ie. Create the Product , then determine the name has been successfully set via the Read Model. But this seems to be a lot for a unit test to take on.


Solution

  • To unit test the successful creation of a product though I need to make the Product Name a read-only public property to test it, but it doesn't seem right to do this just to fulfil a unit test. Without the unit test the Product Name can remain private and everything would work as needed.

    How does data get from your domain model to your persistent storage? How does data get from your "write" model to your "read" model?

    Somewhere in your code base you have either a function, that takes a Product as an input and returns some domain agnostic representation of it (byte[], or JSON, or whatever), or you have a method that takes as arguments a Product and a callback that accepts some domain agnostic representation.

    It might be explicit, or it might be implicit (ORM magic?), but it's going to be there somewhere -- "write only" domain entities aren't very interesting.

    Your tests should be using that same mechanism.

    It may help to keep in mind one of the old understandings of "unit" in "unit test" -- that the test is a single isolated self contained thing, insulated from interference by other tests that may also be running.