Skip to content

RFC: Fluent Testing API #294

Closed
Closed
@jaredcnance

Description

@jaredcnance

Update: I am considering moving this as an add-on to DotnetTestAbstractions.

This is part of the initiative defined by #251.

Status: WIP (feedback desired)

Summary

Provide a fluent testing API that abstracts away the boilerplate required by most json:api requests.

Motivation

Currently, there is a lot of boilerplate required to test a single json:api endpoint. For example, this is one of the tests used against the example app in this repo:

// arrange
var builder = new WebHostBuilder()
.UseStartup<Startup>();
var httpMethod = new HttpMethod("POST");
var server = new TestServer(builder);
var client = server.CreateClient();
var context = _fixture.GetService<AppDbContext>();
var owner = new JsonApiDotNetCoreExample.Models.Person();
context.People.Add(owner);
await context.SaveChangesAsync();
var route = "/api/v1/todo-collections";
var request = new HttpRequestMessage(httpMethod, route);
var content = new
{
data = new
{
type = "todo-collections",
relationships = new
{
owner = new
{
data = new
{
type = "people",
id = owner.Id.ToString()
}
}
}
}
};
request.Content = new StringContent(JsonConvert.SerializeObject(content));
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json");
// act
var response = await client.SendAsync(request);
// assert
Assert.Equal(HttpStatusCode.Created, response.StatusCode);

We should be able to drastically reduce this to something a bit more readable:

// arrange
var expectedOwner = new Person();
var expectedTodoCollection = new TodoCollection();
var request = new CreateRequest<TodoCollection>(expectedTodoCollection)
   // need to add `expectedOwner` to db prior to sending the request
  .WithNewRelationship(todoCollection => todoCollection.Owner, expectedOwner);

// act
var resultantTodoCollection = await request.SendAndValidateAsync();
/* your assertions go here */

Detailed Design

Create a new package JsonApiDotNetCore.Testing

Possible APIs

API Description
JsonApiRequest<T>.SendAndValidateAsync() Sends the request and performs json:api related validations
JsonApiRequest<T>.SendAsync() Sends the request without performing validations
JsonApiRequest<T>.Dump() Writes the HTTP request to the console
CreateRequest<T> RequestBuilder for POST requests
GetRequest<T> RequestBuilder for GET requests
UpdateRequest<T> RequestBuilder for PATCH requests
DeleteRequest<T> RequestBuilder for DELETE requests
BulkRequest RequestBuilder for operations request
IWriteRequest<T>.WithNewRelationship This would create the entity prior to sending the request and then include the rio in the relationships.{}.data element
IRequest<T>.WithHeader Add custom headers
IGetRequest<T>.Filter Add filter
IGetRequest<T>.Sort Add filter
IGetRequest<T>.Sort Add filter
IGetRequest<T>.Include Include relationship
IGetRequest<T>.Page Paginate the request
... ...

Considerations

  • How to provide value and remain ORM agnostic (e.g. WithNewRelationship needs to be able to create the entity prior to sending the request)
  • Can we build transactional testing in by default?
  • We need to be very careful around error handling. If an error occurs, we need to communicate the source of the error and what should be done to remedy it (to the best of our ability) back to the developer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    RFCRequest for comments. These issues have major impact on the direction of the library.enhancementhelp wanted

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions