Context
I'm working on a project that pulls data from AWS using the various AWS SDKs for .NET. This specific example deals with the AWSSDK.IdentityManagement
SDK
The goal is to query information from IAmazonIdentityManagementService
and map it to a model that is helpful to the business domain I'm working in
I've been tasked with writing unit tests for the IamService
class.
Problem
With the Unit Test setups being so verbose, I can't help but think the method I'm Unit Testing (GetIamSummaryAsync
) must be constructed poorly.
I've googled around for things like "Design patterns for mapping multiple data sources to single objects", but the only advice I see given is to use the Adapter or Proxy patterns. I'm not sure how to apply them to this scenario
Question
- Is there a better way I could construct my
IamService
class to make it easier (more succinct) to test? - If the Adapter or Proxy patterns are appropriate for this type of scenario, how would they be applied?
public class IamService : IIamService
{
IAmazonIdentityManagementService _iamClient;
public IamService(IAmazonIdentityManagementService iamClient)
{
_iamClient = iamClient;
}
public async Task<IamSummaryModel> GetIamSummaryAsync()
{
var getAccountSummaryResponse = await _iamClient.GetAccountSummaryAsync();
var listCustomerManagedPoliciesResponse = await _iamClient.ListPoliciesAsync();
var listGroupsResponse = await _iamClient.ListGroupsAsync();
var listInstanceProfilesResponse = await _iamClient.ListInstanceProfilesAsync();
var listRolesResponse = await _iamClient.ListRolesAsync();
var listServerCertificatesResponse = await _iamClient.ListServerCertificatesAsync();
var listUsersResponse = await _iamClient.ListUsersAsync();
IamSummaryModel iamSummary = new IamSummaryModel();
iamSummary.CustomerManagedPolicies.Count = listCustomerManagedPoliciesResponse.Policies.Count;
iamSummary.CustomerManagedPolicies.DefaultQuota = getAccountSummaryResponse.SummaryMap["PoliciesQuota"];
iamSummary.Groups.Count = listGroupsResponse.Groups.Count;
iamSummary.Groups.DefaultQuota = getAccountSummaryResponse.SummaryMap["GroupsQuota"];
iamSummary.InstanceProfiles.Count = listInstanceProfilesResponse.InstanceProfiles.Count;
iamSummary.InstanceProfiles.DefaultQuota = getAccountSummaryResponse.SummaryMap["InstanceProfilesQuota"];
iamSummary.Roles.Count = listRolesResponse.Roles.Count;
iamSummary.Roles.DefaultQuota = getAccountSummaryResponse.SummaryMap["RolesQuota"];
iamSummary.ServerCertificates.Count = listServerCertificatesResponse.ServerCertificateMetadataList.Count;
iamSummary.ServerCertificates.DefaultQuota = getAccountSummaryResponse.SummaryMap["ServerCertificatesQuota"];
iamSummary.Users.Count = listUsersResponse.Users.Count;
iamSummary.Users.DefaultQuota = getAccountSummaryResponse.SummaryMap["UsersQuota"];
return iamSummary;
}
}
Where the class IamSummaryModel
is defined as:
public sealed class IamSummaryModel
{
public ResourceSummaryModel CustomerManagedPolicies { get; set; } = new ResourceSummaryModel();
public ResourceSummaryModel Groups { get; set; } = new ResourceSummaryModel();
public ResourceSummaryModel InstanceProfiles { get; set; } = new ResourceSummaryModel();
public ResourceSummaryModel Roles { get; set; } = new ResourceSummaryModel();
public ResourceSummaryModel ServerCertificates { get; set; } = new ResourceSummaryModel();
public ResourceSummaryModel Users { get; set; } = new ResourceSummaryModel();
}
public sealed class ResourceSummaryModel
{
public int Count { get; set; }
public int DefaultQuota { get; set; }
}
The problem I'm facing is that my Unit Tests turn into a mass of code in the Assemble section. I have to mock every call I make to each AWS SDK client method.
Example Unit Test
[Fact]
public async Task GetIamSummaryAsync_CustomerManagerPolicies_MapToModel()
{
// Arrange
var iamClientStub = new Mock<IAmazonIdentityManagementService>();
iamClientStub.Setup(iam => iam.ListPoliciesAsync(It.IsAny<CancellationToken>()))
.Returns(Task.FromResult(
new ListPoliciesResponse()
{
Policies = new List<ManagedPolicy>()
{
new ManagedPolicy(),
new ManagedPolicy()
}
}
));
// Lots of other mocks, one for each dependency
var sut = new IamService(iamClientStub.Object);
// Act
var actual = await sut.GetIamSummaryAsync();
// Assert
Assert.Equal(2, actual.CustomerManagedPolicies.Count);
}
mock.SetupPolicyListing()