How can I test an Aggregate that relies on time? - java

I am trying to model a time keeping application.
Ordinarily when I have a class that depends on time, I can provide an overloaded constructor or method to be able to inject a Clock into that method or class and be able to test its behavior.
If I have a command that needs to be able to pass the current time into an event, how can this work in the aggregate of an axon based application?
#Aggregate
#Slf4j
public class TimeCard {
#AggregateIdentifier
private String employeeName;
private Instant clockInTime;
public TimeCard() {
//Axon requires empty constructor on aggregate
}
#CommandHandler
public TimeCard(ClockInCommand cmd) {
AggregateLifecycle.apply(new ClockInEvent(cmd.getEmployeeName(), Instant.now()));
}
#EventSourcingHandler
public void on(ClockInEvent event) {
this.employeeName = event.getEmployeeName();
this.clockInTime = event.getClockInTime();
}
}
It seemed that the test fixture handled that cleanly for me by providing methods to provide the time. Here is my test method:
#Test
void testClockInCommand() {
testFixture.givenNoPriorActivity()
.andGivenCurrentTime(clock.instant())
.when(new ClockInCommand("GoldFlsh"))
.expectEvents(new ClockInEvent("GoldFlsh", testFixture.currentTime()));
}
But my event did end up being different by a fraction of a second.
Expected <2020-02-02T13:47:20.684344700Z> but got <2020-02-02T13:47:20.954347700Z>
What's the best way to handle this? Should commands only take in time from upstream? Or can I inject a clock somehow for testing.

When relying on time in Aggregates (and other axon types) you can use the GenericEventMessage.clock which defaults to System.UTC in most runtime configurations.
The Testfixture will override this to be a fixed time during tests. Update the use of Instant.now() to use this clock.
#CommandHandler
public TimeCard(ClockInCommand cmd) {
AggregateLifecycle.apply(new ClockInEvent(cmd.getEmployeeName(), GenericEventMessage.clock.instant()));
}

Related

How to mock LocalDatTime.now() using mockito?

I'm writing unit test to my business class and I would like to mock LocalDateTime to a specific time according to my test. Here is my function:
private fun isExpired(access: Access): Boolean {
return access.validUntil.isAfter(LocalDateTime.now())
}
How can I mock LocalDateTime.now()?
My suggestion is that you inject a dependency on a Clock and use that in your method. Apologies that I've converted to Java as I'm not too familiar with kotlin.
class ClassToTest {
private final Clock;
public ClassToTest(Clock clock) {
this.clock = clock;
}
private boolean isExpired(Access access) {
return access.validUntil.isAfter(LocalDateTime.now(clock));
}
}
And the test that uses a fixed 'now' would look like:
#Test
void testIsExpired() {
Clock clock = mock(Clock.class);
when(clock.instant()).thenReturn(Instant.ofEpochSecond(1000L));
when(clock.getZone()).thenReturn(ZoneOffset.UTC);
ClassToTest test = new ClassToTest(clock);
assertThat(test.isExpired(access))...
}
You specifically asked about mocking but you could achieve the same with a constant clock:
#Test
void testIsExpired() {
Clock clock = Clock.fixed(Instant.ofEpochSecond(1000L), ZoneOffset.UTC);
ClassToTest test = new ClassToTest(clock);
assertThat(test.isExpired(access))...
}
Your production code would inject whichever clock you want (such as a particular TZ, local TZ, clocks that tick each second etc.) which are all created using static Clock methods. The ability to change clocks is often a useful feature to have on top of its value for testing.

How Can I Test Aggregate if ID is randomly generated?

This may be more of a design question but I have an aggregate member that is generated via a command and need to be able to test that the Event is generated given the command was run.
however, I don't see any obvious way to do an anyString match on one field of the event in the TestFixture framework.
Is it "bad practice" to generate IDs in the aggregate when created? Should IDs be generated outside of the aggregate?
#AggregateMember(eventForwardingMode = ForwardMatchingInstances.class)
private List<TimeCardEntry> timeCardEntries = new ArrayList<>();
data class ClockInCommand(#TargetAggregateIdentifier val employeeName: String)
#CommandHandler
public TimeCard(ClockInCommand cmd) {
apply(new ClockInEvent(cmd.getEmployeeName(),
GenericEventMessage.clock.instant(),
UUID.randomUUID().toString()));
#EventSourcingHandler
public void on(ClockInEvent event) {
this.employeeName = event.getEmployeeName();
timeCardEntries.add(new TimeCardEntry(event.getTimeCardEntryId(), event.getTime()));
}
#Data
public class TimeCardEntry {
#EntityId
private final String timeCardEntryId;
private final Instant clockInTime;
private Instant clockOutTime;
#EventSourcingHandler
public void on(ClockOutEvent event) {
this.clockOutTime = event.getTime();
}
private boolean isClockedIn() {
return clockOutTime != null;
}
}
#ParameterizedTest
#MethodSource(value = "randomEmployeeName")
void testClockInCommand(String employeeName) {
testFixture.givenNoPriorActivity()
.when(new ClockInCommand(employeeName))
.expectEvents(new ClockInEvent(employeeName, testFixture.currentTime(), "Any-String-Works"));
}
Is it "bad practice" to generate IDs in the aggregate when created? Should IDs be generated outside of the aggregate?
Random numbers are a lot like clocks - they are a form of shared mutable state. Put another way, they are a concern of the imperative shell, not of the functional core.
What this usually means for your domain model is that the randomness is passed in as an argument, rather than produced by the aggregate itself. This might mean passing an ID generator to the domain model, or even generating the id in the application and passing in the generated identifier as a value.
Thus, in our unit test, we replace the random generator provided by the target application with a "random" generator provided by the test -- because the test controls the generator, the identifier used becomes deterministic, and therefore you can more easily work around it.
In cases where you aren't happy with making the random generator part of the api of your domain model, another option is to expose it as part of the test interface.
// We don't necessarily worry about testing this version, it is "too simple to break"
void doSomethingCool(...) {
doSomethingCool(ID.new, ...);
}
// Unit tests measure this function instead, which is easier to test and has
// all of the complicated logic
void doSomethingCool(ID id, ...) {
// ...
}

aggregate not found in the event store

I am trying to add data using CQRS framework AXON. But while hitting the API(used to add an order). I am getting the below error:-
Command 'com.cqrs.order.commands.CreateOrderCommand' resulted in org.axonframework.modelling.command.AggregateNotFoundException(The aggregate was not found in the event store)
But i already have an Aggregate in my code(OrderAggregate.Java).
The Full code can be found at - https://github.com/iftekharkhan09/OrderManagementSystem
API to add Order - http://localhost:8080/confirmOrder
Request Body:-
{
"studentName":"Sunny Khan"
}
Can anyone please tell me where am i doing wrong?
Any help is appreciated!
For other readers, let me share the Aggregate you've created in your repository:
#Aggregate
public class OrderAggregate {
public OrderAggregate(OrderRepositoryData orderRepositoryData) {
this.orderRepositoryData = orderRepositoryData;
}
#AggregateIdentifier
private Integer orderId;
private OrderRepositoryData orderRepositoryData;
#CommandHandler
public void handle(CreateOrderCommand command) {
apply(new OrderCreatedEvent(command.getOrderId()));
}
#EventSourcingHandler
public void on(OrderCreatedEvent event) {
this.orderId=event.getOrderId();
Order order=new Order("Order New");
orderRepositoryData.save(order);
}
protected OrderAggregate() {
// Required by Axon to build a default Aggregate prior to Event Sourcing
}
}
There are several things you can remove entirely from this Aggregate, which are:
The OrderRepositoryData
The OrderAggregate constructor which sets the OrderRepositoryData
The manually saving of an Order in the #EventSourcingHandler annotated function
What you're doing here is mixing the Command Model's concern of making decisions with creating a queryable Order for the Query Model. It would be better to remove this logic entirely from an Aggregate (the Command Model in your example) and move this to an Event Handling Component.
This is however not the culprit for the AggregateNotFoundException you're receiving.
What you've missed is to make the CreateOrderCommand command handler a constructor.
The CreateOrderCommand will create an Order, as it's name already suggests.
Hence, it should be handled by a constructor rather than a regular method.
So, instead of this:
#CommandHandler
public *void* handle(CreateOrderCommand command) {
apply(new OrderCreatedEvent(command.getOrderId()));
}
You should be doing this:
#CommandHandler
public OrderAggregate(CreateOrderCommand command) {
apply(new OrderCreatedEvent(command.getOrderId()));
}
Hope this helps you out #Sunny!
aggregate not found in the event store
The main reason for this exception is, When the axon is trying to save the aggregate it should create the aggragate first.
#CommandHandler
public OrderAggregate(CreateOrderCommand command) {
apply(new OrderCreatedEvent(command.getOrderId()));
}
Also in this way ur
private OrderRepositoryData orderRepositoryData;
won't be initialized, so autowired the orderRepositoryData also.
#Autowired
private OrderRepositoryData orderRepositoryData;
For the successive events you should use same OrderId ,else also it will throw
handleThrowable(java.lang.Throwable,org.springframework.web.context.request.WebRequest)
org.axonframework.modelling.command.AggregateNotFoundException: The aggregate was not found in the event store
at org.axonframework.eventsourcing.EventSourcingRepository.doLoadWithLock(EventSourcingRepository.java:122)

Unit testing time-based logic in Java

I have a method which implements different logic on data fetched from a DB depending on what the current date is.
I want to test it by having the unit test create objects, save them in the DB and invoke the tested method. However, in order to have predictable results I need to change the system date each time and I don't know how to do that in Java.
Suggestions?
You can generate your expected results using the current date.
Or you write your system to use a date/time you give it when being tested (rather than the clock) That way the time is always what the test expects.
I use something like
interface TimeSource {
long currentTimeMS(); // actually I have currentTimeNS
void currentTimeMS(long currentTimeMS);
}
enum VanillaTimeSource implements TimeSource {
INSTANCE;
#Override
public long currentTimeMS() {
return System.currentTimeMillis();
}
#Override
public void currentTimeMS(long currentTimeMS) {
// ignored
}
}
class FixedTimeSource implements TimeSource {
private long currentTimeMS;
#Override
public long currentTimeMS() {
return currentTimeMS;
}
#Override
public void currentTimeMS(long currentTimeMS) {
this.currentTimeMS = currentTimeMS;
}
}
In tests I use a FixedTimeSource which can be data driven e.g. set by inputs/events. In production I use a VanillaTimeSource.INSTANCE which ignores times in inputs/events and uses the current time.
You need to look at injecting something into your class that allows you to customize the way Time is presented.
For example
public interface TimeProvider {
DateTime getCurrentTime();
}
public class UnderTest {
// Inject this in some way (e.g. provide it in the constructor)
private TimeProvider timeProvider;
public void MyMethod() {
if (timeProvider.getCurrentTime() == "1234") {
// Do something
}
}
}
Now in your unit tests you can provide a fake implementation of time provider. In the real production code you can just return the current date time.
I had a similar problem recently with code I couldn't refactor too much (time constraints, didn't want to inadvertently break anything). It had a method I wanted to test which called System.currentTimeMillis() and the case I wanted to test would depend on what that value returned. Something like:
public class ClassINeedToTest {
public boolean doStuff() {
long l = System.currentTimeMillis();
// do some calculation based on l
// and return the calculation
}
}
To allow unit-testing, I refactored the class so it had a helper method which was protected
protected long getCurrentTimeMillis() {
// only for unit-testing purposes
return System.currentTimeMillis();
}
and this method was called by doStuff(). This didn't change the functionality but now meant that when I call it in the unit-test, I could then override this to return a specific value, like
ClassINeedToTest testClass = new ClassINeedToTest() {
protected long getCurrentTimeMillis() {
// return specific date for my test
return 12456778L;
}
};
boolean result = testClass.doStuff();
// test result with an assert here
This does however mean that I've polluted the interface of my class, so you may decide the cost is too high. There are probably better ways if you can refactor the code more.

Does mockito have an equivalent idiom to jMock's States?

The book Growing Object Oriented Software gives several examples in jMock where the state is made explicit without exposing it through an API. I really like this idea. Is there a way to do this in Mockito?
Here's one example from the book
public class SniperLauncherTest {
private final States auctionState = context.states("auction state")
.startsAs("not joined");
#Test public void addsNewSniperToCollectorAndThenJoinsAuction() {
final String itemId = "item 123";
context.checking(new Expectations() {{
allowing(auctionHouse).auctionFor(itemId); will(returnValue(auction));
oneOf(sniperCollector).addSniper(with(sniperForItem(item)));
when(auctionState.is("not joined"));
oneOf(auction).addAuctionEventListener(with(sniperForItem(itemId)));
when(auctionState.is("not joined"));
one(auction).join(); then(auctionState.is("joined"));
}});
launcher.joinAuction(itemId);
}
}
I used a spy for the self same exercise:
http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#13
I changed my SniperListener mock into a spy thus:
private final SniperListener sniperListenerSpy = spy(new SniperListenerStub());
private final AuctionSniper sniper = new AuctionSniper(auction, sniperListenerSpy);
And also created a stubbed implementation of SniperListener:
private class SniperListenerStub implements SniperListener {
#Override
public void sniperLost() {
}
#Override
public void sniperBidding() {
sniperState = SniperState.bidding;
}
#Override
public void sniperWinning() {
}
}
The book uses JMock's "States", but I used a nested enum instead:
private SniperState sniperState = SniperState.idle;
private enum SniperState {
idle, winning, bidding
}
You then have to use regular JUnit asserts to test for the state:
#Test
public void reportsLostIfAuctionClosesWhenBidding() {
sniper.currentPrice(123, 45, PriceSource.FromOtherBidder);
sniper.auctionClosed();
verify(sniperListenerSpy, atLeastOnce()).sniperLost();
assertEquals(SniperState.bidding, sniperState);
}
Not that I'm aware of. I've used mockito a far amount and there's nothing in the doco similar to what I read on the JMock site about states. If I have it correctly they basically limit the time at which an exepection can occur to the duration of a specific state of another object. It's an interesting idea, but I'm struggling to see the applications for it.
In Mockito you can execute code using Stubbing with callbacks to do the same job. In the callback method you can execute further validations of the state. Alternatively you can employ a Custom argument matcher as they are also executed at the time of the call.
Both of these give you access to the code at execution time which is the time you want to check the state.

Categories