I need to test a method that depends on the object System.Fabric.FabricClient. Specifically, the method reads a list of Partitions from this object:
ServicePartitionList partitions = await this.fabricClient.QueryManager.GetPartitionListAsync(serviceName);
Then, the method goes through the list and obtains data for each partition.
foreach (Partition partition in partitions)
{
// ... code to verify
LowKey = ((Int64RangePartitionInformation)partition.PartitionInformation).LowKey;
PartitionId = partition.PartitionInformation.Id;
Health = partition.HealthState;
// ... code to verify
}
I'm using moq library for mock interfaces but I can't use it with this concrete class.
I've tried wrapping the FabricClient with an interface but all the objects implicated are abstract or sealed and I have been unable to instantiate these objects.
I also tried to use ServiceFabric.Mocks but I had no luck. I think FabricClient needs the service running to work.
As a summary, what I need is that the FabricClient object does not throw me any errors when I try to read the partition list and, if possible, get fake values from it.
Edit:
Finally, I've wrapped all the objects I needed from the FabricClient object and exposed them through an interface:
public interface IFabricClientWrapper
{
Task<ServicePartitionListWrapper> GetPartitionListAsync(Uri serviceName);
}
public class FabricClientWrapper : IFabricClientWrapper
{
private FabricClient fabricClient;
public FabricClientWrapper()
{
fabricClient = new FabricClient();
}
public async Task<ServicePartitionListWrapper> GetPartitionListAsync(Uri serviceName)
{
var list = new ServicePartitionListWrapper();
var partitionList = await fabricClient.QueryManager.GetPartitionListAsync(serviceName);
foreach (var partition in partitionList)
{
PartitionWrapper partitionWrapper = new PartitionWrapper();
partitionWrapper.Id = partition.PartitionInformation.Id;
partitionWrapper.HealthState = partition.HealthState;
partitionWrapper.LowKey = ((Int64RangePartitionInformation)partition.PartitionInformation).LowKey;
partitionWrapper.HighKey = ((Int64RangePartitionInformation)partition.PartitionInformation).HighKey;
list.Add(partitionWrapper);
}
return list;
}
}
public class ServicePartitionListWrapper : List<PartitionWrapper> { }
public class PartitionWrapper
{
public Guid Id { get; set; }
public HealthState HealthState { get; set; }
public long LowKey { get; set; }
public long HighKey { get; set; }
}
FabricClient is tightly coupled to the cluster runtime.
You could use a layer of abstraction here. Instead of calling the QueryManager directly, wrap it inside another class similar to this:
public class PartitionInfoProvider : IPartitionInfoProvider
{
private FabricClient fabricClient;
public PartitionInfoProvider(FabricClient fabricClient)
{
this.fabricClient = fabricClient;
}
public Task<ServicePartitionList> GetPartitions()
{
return this.fabricClient.QueryManager.GetPartitionListAsync(serviceName);
}
}
Pass the implementation to the Service constructor, using the interface declaration.
You can then mock provide a mock implementation of this provider, when running your test.