Previously I explained how the test definition works. In this post I’ll show how we declare tests and get access to the infrastructure provided by the stateful service. Components that are used inside a stateful service most likely end-up using either the StatefulServiceContext, the IStatefulServicePartition, the IReliableStateManager or other methods and properties provided by the stateful service inheritance hierarchy. Let’s have an oversimplified look at how the hierarchy looks like:
public abstract class StatefulServiceBase : IStatefulUserServiceReplica { public StatefulServiceContext Context { get; } protected IStatefulServicePartition Partition { get; } // more not of interest } public abstract class StatefulService : StatefulServiceBase { public IReliableStateManager StateManager { get; } // more not of interest }
So any component that needs to for example use the IReliableStateManager inject the state manager. This doesn’t require magic like Inversion of Control containers since the stateful service declaration or the endpoint communication listeners provided by it should be the composition root of the infrastructure used by the service. Below is a short, simplified and contrived example how such a code might look like.
sealed class OrderShippingService : StatefulService { protected override Task RunAsync(CancellationToken cancellationToken) { var orderShipping = new OrderShipping(StateManager); while(!cancellationToken.IsCancellationRequested) { await orderShipping.ShipIt(cancellationToken).ConfigureAwait(false); } } } class OrderShipping { public OrderShipping(IReliableStateManager stateManager) { this.stateManager = stateManager; } public async Task ShipIt(CancellationToken token) { var dictionary = await stateManager .GetOrAddAsync<IReliableDictionary<string, long>>("ordersShipped", TimeSpan.FromSeconds(5)) .ConfigureAwait(false); using(var tx = stateManager.CreateTransaction()) { long count = await wordCountDictionary .AddOrUpdateAsync(tx, "FancyJackets", 1, (key, oldValue) => oldValue + 1) .ConfigureAwait(false); await tx.CommitAsync().ConfigureAwait(false); } } }
The component does nothing fancy here. I gets access to the reliable dictionary called ordersShipped and transactionally increments the counter under the key FancyJackets. To test this component with an integration test it is now possible to write the following code.
[TestFixture] public class OrderShippingTests : INeed<IReliableStateManager> { IReliableStateManager stateManager; [Test] public async Task Should_increment_the_counter() { // Arrange var testee = new OrderShipping(stateManager); // Act await testee.ShipIt(CancellationToken.None) .ConfigureAwait(false); // Assert var dictionary = await stateManager.GetOrAddAsync<IReliableDictionary<string, long>>("ordersShipped", TimeSpan.FromSeconds(5)); // .. you'll get the point } public void Need(IReliableStateManager dependency) { stateManager = dependency; } }
As the example test code above shows with the Service Fabric testing approach outlined in my series wheenver a test needs access to the reliable state manager, the stateful service context or the partition information it can implement the `INeed
public class TestNeedingAllDependencies: INeed<IStatefulServicePartition>, INeed<StatefulServiceContext>, INeed<IReliableStateManager> { public void Need(IReliableStateManager dependency) => stateManager = dependency; public void Need(IStatefulServicePartition dependency) => servicePartition = dependency; public void Need(StatefulServiceContext dependency) => serviceContext = dependency; }
Or if we prefer to use the OrderShippingService as an entry point for the tests we can implement `INeed
public class TestNeedingAllDependencies: INeed<OrderShippingService> { public void Need(OrderShippingService dependency) => shippingService = dependency; }
In the next post I’m going to walk you through the infrastructure bits and pieces that make this possible. Stay tuned.
[…] the last post, I showed how it is possible to write test fixture that gets access to the reliable state manager […]
Really cool blog posts! Thanks a lot.
Did you find a way to debug the tests in your repo?
Thanks for the feedback. Unfortunately not. I raised https://stackoverflow.com/questions/42827223/service-fabric-debugging-with-codepackagedebugparameters and together with Tomasz (see first upvoted answer) we tried to dig deeper but couldn’t get it working. When then decided to stick to attach to process only.