Given, when, then testing

I've got the following failing test code (in groovy, more about that
when I've finished my test setup, but it has been nice to write tests
in so far):

@Test
def "create bid order in empty order book"() {
    given()

    .when (new CreateOrderCommand(
        reference : "first-bid-order",
        side : Bid,
        price : 100.money,
        volume : 100.volume
        )
    )

    .expectVoidReturnType()

    .expectEvents(
        new OrderCreatedEvent( new Order(
        orderId : new
OrderId("10000000-0000-0000-0000-000000000000"),
        timestamp : "2010-10-10 12:00:00".timestamp,
        side : Bid,
        price : 100.money,
        volume : 100.volume
        ))
    )
}

The (pretty obvious) error is this

In an event of type [OrderCreatedEvent], the property [order]
(declared in [OrderEvent]) was not as expected.
Expected <Order [orderId=10000000-0000-0000-0000-000000000000,
    timestamp=Sun Oct 10 12:00:00 CEST 2010,
    side=Bid,
    price=100,
    volume=100]>

but got <Order [orderId=d6b80082-0743-40af-ac6a-d3866d5797dd,
    timestamp=Fri Nov 19 02:52:13 CET 2010,
    side=Bid,
    price=100,
    volume=100]>

The reason is that I cannot now the ID (set to a random UUID by the
command handler) of the newly created order before it is created and
the same goes for the timestamp. For the timestamp I think that the
test fixture could have a helper method for that. What can I do about
the ID? Do I have to let the client send an ID in with the command? I
guess it is ok since it is a UUID, but it feels strange. There's no
guaranty that the client actually generates a random UUID.

I guess the time does not really matter here since

"All events are compared for equality using a shallow equals
comparison on all the fields of the events. This means that all
assigned values on the events' fields should have a proper equals
implementation."

and that means that it is .equals() on Order that determines if the
two events are equal. In there I only check the orderId, which fails
since I don't know the orderId.

But perhaps time values can be of interest in other tests.

Is the Order object your aggregate? In you event, you should never expose the aggregate itself.

The aggregate identifier in given-when-then tests can be retrieved using fixture.getAggregateIdentifier. The best way to predict UUID’s (or whatever type of identifier you use) is by using client generated identifiers. In you create command, provide the identifier that the aggregate should be created with. It makes a lot of things much easier.

The expectEvents method you’re using does a shallow comparison of actual and expected events. If that’s not what you want, you should use the expectEvents method that accepts a (Hamcrest) matcher. The matchers give you all the freedom you need. The matcher receives the list of events and can -based on that list- decide if the list is accepted or not.

Another tip: if you use JodaTime for your timestamps, there is a utility class (I think it’s called JodaTimeUtils) that allows you to set the “current time” to a specific value. It’s especially useful for testing, since you can predict what dates it creates.

Cheers,

Allard

I overlooked this remark:
“There’s no guaranty that the client actually generates a random UUID.”

So what? If the client bases its UUID on the state of something, or uses a sequential UUID, who cares? The only thing you care about is that the UUID is unique. And that’s easy, since the event will clash with an existing event in the events store if the aggregate identifier isn’t unique.

Cheers,

Allard

PS. Are you using axon 0.6 or 0.7-snapshot?

I overlooked this remark:
"There's no guaranty that the client actually generates a random UUID."

> So what? If the client bases its UUID on the state of something, or
uses a

sequential UUID, who cares? The only thing you care about is that the UUID
is unique. And that's easy, since the event will clash with an existing
event in the events store if the aggregate identifier isn't unique.

With "client" I was talking about any code out of my control. The
point with UUID is to have uniqueness and make the IDs harder to
guess. If I allow my clients (code written by someone else using my
system) to use sequential UUIDs the "hard to guess" part is not
enforced even if I can check the uniqueness. Is my thinking wrong
here?

This was with 0.6.1. I'd like to start using 0.7 though.

> Is the Order object your aggregate? In you event, you should never expose
> the aggregate itself.

The aggregate is an OrderBook. The order book contains orders. Orders
are immutable and I thought it was a good idea to send a copy out with
the OrderCreatedEvent instead of duplicating the fields in the event
itself. Is this bad?

> The aggregate identifier in given-when-then tests can be retrieved using
> fixture.getAggregateIdentifier.

Yeah, I do that with the OrderBookId, so no problem there.

>The best way to predict UUID's (or whatever
> type of identifier you use) is by using client generated identifiers. In you
> create command, provide the identifier that the aggregate should be created
> with. It makes a lot of things much easier.

Yeah, I'm starting to lean towards that way of doing it. It sure makes
it easier since the client already knows what ID too look for in the
event stream, and the command does not have to return anything.

> The expectEvents method you're using does a shallow comparison of actual
> and expected events. If that's not what you want, you should use the
> expectEvents method that accepts a (Hamcrest) matcher. The matchers give you
> all the freedom you need. The matcher receives the list of events and can
> -based on that list- decide if the list is accepted or not.

Ah, that's nice.

> Another tip: if you use JodaTime for your timestamps, there is a utility
> class (I think it's called JodaTimeUtils) that allows you to set the
> "current time" to a specific value. It's especially useful for testing,
> since you can predict what dates it creates.

Thanks. I have to look into that.

So if I understand correctly, your Order is a value object. In that case, it's perfectly fine to include them in an event. I tend to include all fields in a value object's equals method. "officially", they don't have an explicit identifier.

The primary goal of the uuid identifier is not to prevent clients from guessing an identifier, but to make it nearly impossible for a client to generate a clashing id.

Clients don't need to guess id's. They can just query for them.

Cheers,

Allard