I have biz code that finds changes (candidates) in a DB and publishes (sends) them to azure event hub via EventHubProducerClient, but finding it very hard in unit tests that my candidates are publishing correctly when introducing EventDataBatch to work within the publishing limits.
I used to just mock the client and Stub out EventHubProducerClient's SendAsync capturing (actually i had a custom matcher, but effectively it's just capturing for purpose of comparing) the EventData's that were sent to make sure my candidates are going out correctly.
But when i hit 1M send event limits for my batch i wanted to leverage EventDataBatch to make sure i stay under the limit. However i'm finding EventDataBatch rather frusturating as it's sealed and all it's interesting stuff (like getting to the events like AmqpProducer does https://github.com/Azure/azure-sdk-for-net/blob/6011385c397ffa881d9d7e6bf8c448ad4ee47665/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpProducer.cs#L233) are internal methods...so short of verifying the count...there's really no much i can do outside of using reflection (which is what i've ended up doing).
Am i missing something here? or was this just an oversite in v4 to v5 upgrade (where ToEnumerable() was dropped on EventDataBatch )
Closest i found was EventHubProducerClient unit testing in c# but seems like the answer was skipping on the important nuance of EventDataBatch's unit testability problems.
CodePudding user response:
For unit testing, you'll want to create the batch via the EventHubsModelFactory. Its EventDataBatch method accepts a List<EventData>
that the batch will use as a backing store. Each event that TryAdd
accepts will be placed in that list.
Example:
var eventLimit = 3;
var store = new List<EventData>();
var batch = EventHubsModelFactory.EventDataBatch(
5,
store,
tryAddCallback: _ => store.Count < eventLimit);
while (store.Count < eventLimit)
{
var eventData = new EventData("Test")
{
MessageId = store.Count.ToString()
};
Assert.That(
() => batch.TryAdd(eventData),
Is.True,
$"The batch contains { store.Count } events; adding another should be permitted.");
}
Assert.That(
store.Count,
Is.EqualTo(eventLimit),
"The batch should be at its limit.");
Assert.That(
() => batch.TryAdd(new EventData("Too many")),
Is.False,
"The batch is full; it should not be possible to add a new event.");
for (var index = 0; index < eventLimit; index)
{
Assert.That(
store.Any(eventData => eventData.MessageId == index.ToString()),
Is.True,
$"The message for { index } should be in the batch.");
}
The AsEnumerable
method was removed in Azure.Messaging.EventHubs
because the batch does not keep a reference to the raw EventData
instance when accepted. Since it must be serialized to AMQP format in order to measure its size, the batch keeps a reference to that serialized version. This allows it to avoid paying the serialization cost multiple times. It also also ensures that the integrity of the batch is maintained by disallowing mutation its data should the properties of an event be changed after it was accepted into the batch.
This is necessary to ensure the size measurement and results of TryAdd
are accurate.