.Net Core DynamodDB unit testing with XUnit - amazon-web-services

Using C#, .net core 2.0, dynamo db
I have my web api, that interact with my dynamo db database having both Get and Post methods.
Example of Mehthod:
[HttpGet("api/data")]
public async Task<List<string>> GetAllData(string userId, string type, string status)
{
var creds = new BasicAWSCredentials(awsId, awsPassword);
var dynamoClient = new AmazonDynamoDBClient(creds, dynamoRegion);
var context = new DynamoDBContext(dynamoClient);
List<ScanCondition> conditions = new List<ScanCondition>();
conditions.Add(new ScanCondition("UserId", ScanOperator.Equal, userId));
conditions.Add(new ScanCondition("Type", ScanOperator.Equal, type));
conditions.Add(new ScanCondition("Status", ScanOperator.Equal, status));
var results = await context.ScanAsync<Common.Job>(conditions, new DynamoDBOperationConfig() { OverrideTableName = MyDynamoTable }).GetRemainingAsync();
return results.Select(x => x.UpdatedBy.ToLower()).ToList();
}
Now I want to write unit/integration tests for my api methods. Earlier I had used NUnit but with .net core 2.0 I believe we have to use XUnit: https://xunit.github.io/docs/getting-started-dotnet-core
Setting up Xunit in my project should not be an issue.
I wanted to know how can I write test which involve dynamo db here. This is the first time I am using any AWS service here.
So bascially I need to know how can I mock up a aws connection, dynamo db and then use various params as shown in my method above.
I could not find much details or any earlier helpful post on this topic so posting one here.
If aws dynamo db part is not testable. Can anyone share the example of xunit test where we can test the params may be and see the expected result?

AWS SDK work with interfaces. You can mock interface IAmazonDynamoDB easily. But try to do it with dependecy injection-ish. Much better.
Something like
private readonly IAmazonDynamoDB dynamodbClient;
private readonly IDynamoDBContext context;
public MyDynamodbHandler(IAmazonDynamoDB client)
{
this.dynamodbClient = client;
this.context = new DynamoDBContext(client);
}
[HttpGet("api/data")]
public async Task<List<string>> GetAllData(string userId, string type, string status)
{
List<ScanCondition> conditions = new List<ScanCondition>();
conditions.Add(new ScanCondition("UserId", ScanOperator.Equal, userId));
conditions.Add(new ScanCondition("Type", ScanOperator.Equal, type));
conditions.Add(new ScanCondition("Status", ScanOperator.Equal, status));
var results = await this.context.ScanAsync<Common.Job>(conditions, new DynamoDBOperationConfig() { OverrideTableName = MyDynamoTable }).GetRemainingAsync();
return results.Select(x => x.UpdatedBy.ToLower()).ToList();
}
So every function uses the injected IAmazonDynamoDB. All you have to do is to mock this instance at the beginning
Such as
dynamodbClientMock = new Mock();
Then use this mock to initiate MyDynamodbHandler class
var dynamodbHandler = new MyDynamodbHandler(dynamodbClientMock);
dynamodbHandler.GetAllData();

Related

How to request response from .net core to aws amplify GraphQL

Recently, I'm working on AWS Amplify, Which has java and javaScripts related example, but no .net related example. after next i solved this below the way. Here is my question this is the only process to request or response, another way that i missed.
const string query = "query ";
var serializer = new NewtonsoftJsonSerializer();
using var graphQlClient = new GraphQLHttpClient("https://xx.xx.xx.amazonaws.com/graphql", serializer);
graphQlClient.HttpClient.DefaultRequestHeaders.Add("x-api-key", "<api key>");
var subscriptionStream = await graphQlClient.SendQueryAsync<dynamic>(query);
I expect a better way, except my current code.

Azure Function: how can I improve the Unit test?

Azure function based on .Net core 3.1. Triggered when a file is uploaded into the Blob container. Any files uploaded to Azure Blob Storage are compressed, and the database is updated.
Below is my business logic
public partial class FileProcessingServiceFacade : IFileProcessingServiceFacade
{
public async Task<string> ProcessAsync(Stream myBlob, string name, ILogger log, ExecutionContext context)
{
AppDbContext.FileRecords.Add(new FileRecords { ... });
AppDbContext.SaveChanges();
return await Task.FromResult($"success");
}
}
public partial class FileProcessingServiceFacade : ServiceBase<FileProcessingServiceFacade>
{
public FileProcessingServiceFacade(AppDbContext appDbContext, IOptions<AppConfigurator> configurator)
: base(appDbContext, configurator) { }
}
I am using xUnit and MOQ for unit testing and below is my unit test
[Fact]
public void ProcessAsync()
{
var filename = "fileName.csv";
var stream = new MemoryStream(File.ReadAllBytes(filename));
var log = Mock.Of<ILogger>();
var executionContext = Mock.Of<ExecutionContext>();
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase(databaseName: "Testing")
.Options;
var appDbContext = new AppDbContext(options);
var appSettings = new AppConfigurator(){ ... };
IOptions<AppConfigurator> configurator = Options.Create(appSettings);
var target = new FileProcessingServiceFacade(appDbContext, configurator);
var actual = target.ProcessAsync(stream, filename, log, executionContext);
Assert.True(appDbContext.FileRecords.FirstAsync<FileRecords>().Result.FileName.Equals(filename));
Assert.True(actual.Result.Equals("success"));
stream.Dispose();
}
I am trying to improve the code quality of the unit testing and I would appreciate any suggestions.
The Application test involves one or more external systems, below are the sample points which you need to be aware while have unit testing
Tests may fail if you ae connecting your application with Remote System or External System.
You need to call the external system directly.
Accessing external system may have an effect on the performance of your tests.
Also, As suggested by BrettMiller you can go through the sample of Azure functions Test fixture.

Unit Test Web API - How to get auth token

I use token auth for my WebApi application.
I have the following ConfigureAuth method in Startup class:
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
and ApplicationOAuthProvider:
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly string _publicClientId;
public ApplicationOAuthProvider(string publicClientId)
{
if (publicClientId == null)
{
throw new ArgumentNullException("publicClientId");
}
_publicClientId = publicClientId;
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
var user = await userManager.FindAsync(context.UserName, context.Password);
//ApplicationUser user = new ApplicationUser() { UserName ="a" };
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
so, I should call /Token and pass credentials to get token. It works, but I want to create Unit Test for it. Is it possible?
The only way to do that is by make an integration test, which asserts the full pipeline testing - from request to response. Before the actual test on the server, you can call the token endpoint to get it, and then use it in the actual unit test by attaching it to the response. I have a sample, which uses MyTested.WebApi here:
Sample
You can do the same without the testing library, this is just how to do it.
I like the idea of pluggable configuration.
For Unit Test project, I want to use specific identity and get predictable data fro LDAP. So, i use the following line in my unit test method when setting http configuration:
config.Filters.Add(new WebApiSetIdentityFilter(config, identityName));
where the filter just "hacks" the identity, replacing the fields I need:
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
//This principal flows throughout the request.
context.Principal = new GenericPrincipal(new GenericIdentity(this.IdentityName, "LdapAuthentication"), new string[0]);
}

Controller.MyMethod() doesn't kick off HttpModule, so how can I unit test an HttpModule?

How do I unit test a Web Api 2 HttpModule? The module checks for specific HTTP headers.
I tried the following code, but it doesn't kick off the HttpModule.
var logger = new Mock<ILogger>();
var controller = new FeaturesV1Controller(logger.Object);
var controllerContext = new HttpControllerContext();
var request = new HttpRequestMessage();
request.Headers.Add("X-My-Header", "success");
controllerContext.Request = request;
controller.ControllerContext = controllerContext;
// Act
var result = controller.Get(11);
I've verified for real calls, that the HttpModule does get called.
You can find information about how to unit test a HttpModule here.
An alternative could be to not test the module itself but to move out the code that you want to test to another class. By injecting stuff into the request you’re not testing your code, you’re testing the framework. Unless that is what you want to test I would recommend you to move that code out from the HttpModule.

Calling WebAPI in UnitTest TestInitialize

im trying to write a UnitTest for a WebAPI and EF
Im trying to add Data do the database in den TestInitialize, but it didnt work. When i do the same command in a Console Applications, it works.
Is there a different in calling that webapi for tests?
[TestInitialize]
public void CreateEntityObjects()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:60609/");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Department dep1 = new Department() { Id = Guid.NewGuid(), Name = "IT" };
client.PostAsJsonAsync("api/Department", dep1);
}
Edit:
So i still just do the initialize no cleanup (later). I was looking manually if there is some data in the database. But no data, no Error, nothing.
You may try looking at the result property of the request:
var response = client.PostAsJsonAsync("api/Department", dep1).Result;
and then look at what does the server return:
string responseContent = response.Result.Content.ReadAsStringAsync().Result;
Now analyze the responseContent variable to see what possible error message you might have gotten from the server. Also you probably want to self-host your Web API in the unit test before sending an HTTP request to it, otherwise your API might not even be started.