All Projects → adrianiftode → FluentAssertions.Web

adrianiftode / FluentAssertions.Web

Licence: Apache-2.0 license
FluentAssertions for HTTP APIs

Programming Languages

C#
18002 projects

Projects that are alternatives of or similar to FluentAssertions.Web

Aspnetcore Tests Sample
A project to help demonstrate how to do unit, integration and acceptance tests with an web api project using ASP.NET Core and Angular 7 front end.
Stars: ✭ 40 (-43.66%)
Mutual labels:  unit-testing, asp-net-core
MinimalApi
ASP.NET Core 7.0 - Minimal API Example - Todo API implementation using ASP.NET Core Minimal API, Entity Framework Core, Token authentication, Versioning, Unit Testing, Integration Testing and Open API.
Stars: ✭ 156 (+119.72%)
Mutual labels:  unit-testing, asp-net-core
Abot
Cross Platform C# web crawler framework built for speed and flexibility. Please star this project! +1.
Stars: ✭ 1,961 (+2661.97%)
Mutual labels:  unit-testing, netcore
Winton.extensions.configuration.consul
Enables Consul to be used as a configuration source in dotnet core applications
Stars: ✭ 239 (+236.62%)
Mutual labels:  netcore, asp-net-core
eat
Json based scenario testing tool(which can have test for functional and non-functional)
Stars: ✭ 41 (-42.25%)
Mutual labels:  unit-testing, functional-testing
Cqrs Clean Eventual Consistency
CQRS, using Clean Architecture, multiple databases and Eventual Consistency
Stars: ✭ 247 (+247.89%)
Mutual labels:  netcore, asp-net-core
Hexagonal-architecture-ASP.NET-Core
App generator API solution template which is built on Hexagnonal Architecture with all essential feature using .NET Core
Stars: ✭ 57 (-19.72%)
Mutual labels:  unit-testing, asp-net-core
Elmahcore
ELMAH for Net.Standard and Net.Core
Stars: ✭ 127 (+78.87%)
Mutual labels:  netcore, asp-net-core
Awesome-Nuget-Packages
📦 A collection of awesome and top .NET packages sorted by most popular needs.
Stars: ✭ 87 (+22.54%)
Mutual labels:  netcore, asp-net-core
XAF Security E4908
This repository contains examples for Role-based Access Control, Permission Management, and OData / Web / REST API Services for Entity Framework and XPO ORM
Stars: ✭ 47 (-33.8%)
Mutual labels:  netcore, asp-net-core
Netcorecms
NetCoreCMS is a modular theme supported Content Management System developed using ASP.Net Core 2.0 MVC. Which is also usable as web application framework. This project is still under development. Please do not use before it's first release.
Stars: ✭ 165 (+132.39%)
Mutual labels:  netcore, asp-net-core
csharp
📚 Recursos para aprender C#
Stars: ✭ 37 (-47.89%)
Mutual labels:  netcore, asp-net-core
Dockerize.net
.NET Cli Tool to package your .NET Core Application into a docker image: 'dotnet dockerize'
Stars: ✭ 162 (+128.17%)
Mutual labels:  netcore, asp-net-core
tdd roman csharp
Kata: TDD Arabic to Roman Numerals with C#
Stars: ✭ 14 (-80.28%)
Mutual labels:  unit-testing, netcore
Formhelper
ASP.NET Core - Transform server-side validations to client-side without writing any javascript code. (Compatible with Fluent Validation)
Stars: ✭ 155 (+118.31%)
Mutual labels:  netcore, asp-net-core
Onion Architecture Asp.net Core
WhiteApp API solution template which is built on Onion Architecture with all essential feature using .NET 5!
Stars: ✭ 196 (+176.06%)
Mutual labels:  unit-testing, asp-net-core
Efcoreinaction Secondedition
Supporting repo to go with book "Entity Framework Core in Action", second edition
Stars: ✭ 96 (+35.21%)
Mutual labels:  netcore, asp-net-core
Gitserver
ASP.NET Core Git HTTP Server
Stars: ✭ 98 (+38.03%)
Mutual labels:  netcore, asp-net-core
statiq-starter-kontent-lumen
Lumen is a minimal, lightweight, and mobile-first starter for creating blogs using Statiq and Kontent by Kentico.
Stars: ✭ 22 (-69.01%)
Mutual labels:  netcore, asp-net-core
grandnode2
Free, Open source, Fast, Headless, Multi-tenant eCommerce platform built with .NET Core, MongoDB, AWS DocumentDB, Azure CosmosDB, LiteDB, Vue.js.
Stars: ✭ 626 (+781.69%)
Mutual labels:  netcore, asp-net-core

FluentAssertions.Web

This is a FluentAssertions extension over the HttpResponseMessage object.

It provides assertions specific to HTTP responses and outputs rich erros messages when the tests fail, so less time with debugging is spent.

Build status Quality Gate Status NuGet

[Fact]
public async Task Post_ReturnsOk()
{
    // Arrange
    var client = _factory.CreateClient();

    // Act
    var response = await client.PostAsync("/api/comments", new StringContent(@"{
              ""author"": ""John"",
              ""content"": ""Hey, you...""
            }", Encoding.UTF8, "application/json"));

    // Assert
    response.Should().Be200Ok();
}

Why?

Writing tests for ASP.NET Core APIs and or any APIs by using the HttpClient classes leads to some repetitive code and also often to an incomplete one. When the test fails, the developer needs to debug the test in order to assess the failure reason, as the test itself did not usually consider what happens in this case.

Thus this library solves two problems:

Focus on the Assert part and not on the HttpClient related APIs, neither on the response deserialization

Once the response is ready you'll want to assert it. With first level properties like StatusCode is somehow easy, especially with FluentAssertions, but often we need more, like to deserialize the content into an object of a certain type and then to Assert it. Or to simply assert something about the response content itself. Soon duplication code occurs and the urge to reduce it is just the next logical step.

Debugging failed tests interrupts the programmer's flow state

When a test is failing, the following actions are taken most of the time:

  • attach the debugger to the line containing var response = await client..
  • debug the failing test
  • add an Watch for response.Content.ReadAsStringAsync().Result and see the actual response content

And this can be avoided, if the Test Detail Summary contains the request and the response information, providing a similar experience as with an HTTP interceptor like Fiddler.

FailedTest1

FluentAssertions.Web Examples

  • Asserting that the response content of a HTTP POST request is equivalent to a certain object
[Fact]
public async Task Post_ReturnsOkAndWithContent()
{
    // Arrange
    var client = _factory.CreateClient();

    // Act
    var response = await client.PostAsync("/api/comments", new StringContent(@"{
                ""author"": ""John"",
                ""content"": ""Hey, you...""
            }", Encoding.UTF8, "application/json"));

    // Assert
    response.Should().BeAs(new
    {
        Author = "John",
        Content = "Hey, you..."
    });
}
  • Asserting that the response is 200 OK and the content is like an array of specific objects:
[Fact]
public async Task Get_Returns_Ok_With_CommentsList()
{
    // Arrange
    var client = _factory.CreateClient();

    // Act
    var response = await client.GetAsync("/api/comments");

    // Assert
    response.Should().Be200Ok().And.BeAs(new[]
    {
        new { Author = "Adrian", Content = "Hey" }
    });
}
  • Asserting that the response is a HTTP 400 BadRequest and contains a single error message
[Fact]
public async Task Post_WithNoAuthorButWithContent_ReturnsBadRequestWithAnErrorMessageRelatedToAuthorOnly()
{
    // Arrange
    var client = _factory.CreateClient();

    // Act
    var response = await client.PostAsync("/api/comments", new StringContent(@"{
                                    ""content"": ""Hey, you...""
                                }", Encoding.UTF8, "application/json"));

    // Assert
    response.Should().Be400BadRequest()
        .And.OnlyHaveError("Author", "The Author field is required.");
}
  • Asserting the response content once deserialized into a strongly typed object it satisfies a certain assertion
[Fact]
public async Task Get_Returns_Ok_With_CommentsList_With_TwoUniqueComments()
{
    // Arrange
    var client = _factory.CreateClient();

    // Act
    var response = await client.GetAsync("/api/comments");

    // Assert
    response.Should().Satisfy<IEnumerable<Comment>>(model => 
            model.Should().HaveCount(2).And.OnlyHaveUniqueItems(c => c.CommentId));
}
  • Asserting the response content once deserialized into a anonymous object it satisfies a certain assertion
[Fact]
public async Task Get_WithCommentId_Returns_A_NonSpam_Comment()
{
    // Arrange
    var client = _factory.CreateClient();

    // Act
    var response = await client.GetAsync("/api/comments/1");

    // Assert
    response.Should().Satisfy(givenModelStructure: new
    {
        Author = default(string),
        Content = default(string)
    }, assertion: model =>
        {
            model.Author.Should().NotBe("I DO SPAM!");
            model.Content.Should().NotContain("BUY MORE");
        });
}
  • Asserting the response has a header like X-Correlation-ID header of application/json; charset=utf-8
[Fact]
public async Task Get_Should_Contain_a_Header_With_Correlation_Id()
{
    // Arrange
    var client = _factory.CreateClient();

    // Act
    var response = await client.GetAsync("/api/values");

    // Assert
    response.Should().HaveHeader("X-Correlation-ID").And.Match("*-*", "we want to test the correlation id is a Guid like one");
}

Many more examples can be found in the Samples projects and in the Specs files from the FluentAssertions.Web.Tests project

Optional Global Configuration

Deserialization

System.Text.Json

By default System.Text.Json is used to deserialize the response content. The related System.Text.Json.JsonSerializerOptions used to configure the serializer is accessible via the SystemTextJsonSerializerConfig.Options static field from FluentAssertions.Web. So if you want to make the serializer case sensitive, then the related setting is changed like this:

SystemTextJsonSerializerConfig.Options.PropertyNameCaseInsensitive = false; 

The change must be done before the test is run and this depends on the testing framework. Check the NewtonsoftSerializerTests from this repo to see how it can be done with xUnit.

Newtonsoft.Json

The serializer itself is replaceable, so you can implement your own, by implementing the ISerialize interface. The serializer is shipped via the FluentAssertions.Web.Serializers.NewtonsoftJson package.

NuGet

To set the default serializer to Newtonsoft.Json one, use the following configuration:

FluentAssertionsWebConfig.Serializer = new NewtonsoftJsonSerializer();

The related Newtonsoft.Json.JsonSerializerSetttings used to configure the Newtonsoft.Json serializer is accesible via the NewtonsoftJsonSerializerConfig.Options static field. So if you want to add a custom converter, then the related setting is changed like this:

NewtonsoftJsonSerializerConfig.Options.Converters.Add(new YesNoBooleanJsonConverter());

Full API

HttpResponseMessageAssertions Contains a number of methods to assert that an HttpResponseMessage is in the expected state related to the HTTP content.
Should().BeAs<TModel>() Asserts that HTTP response content can be an equivalent representation of the expected model.
Should().HaveHeader() Asserts that an HTTP response has a named header.
Should().NotHaveHeader() Asserts that an HTTP response does not have a named header.
Should().HaveHttpStatus() Asserts that a HTTP response has a HTTP status with the specified code.
Should().NotHaveHttpStatus() that a HTTP response does not have a HTTP status with the specified code.
Should().MatchInContent() Asserts that HTTP response has content that matches a wildcard pattern.
Should().Satisfy<TModel>() Asserts that an HTTP response content can be a model that satisfies an assertion.
Should().Satisfy<HttpResponseMessage>() Asserts that an HTTP response content can be a model that satisfies an assertion.
Should().HaveHeader().And. Contains a number of methods to assert that an HttpResponseMessage is in the expected state related to HTTP headers.
BeEmpty() Asserts that an existing HTTP header in a HTTP response has no values.
BeValues() Asserts that an existing HTTP header in a HTTP response has an expected list of header values.
Match() Asserts that an existing HTTP header in a HTTP response contains at least a value that matches a wildcard pattern.
Should().Be400BadRequest().And. Contains a number of methods to assert that an HttpResponseMessage is in the expected state related to HTTP Bad Request response
HaveError() Asserts that a Bad Request HTTP response content contains an error message identifiable by an expected field name and a wildcard error text.
OnlyHaveError() Asserts that a Bad Request HTTP response content contains only a single error message identifiable by an expected field name and a wildcard error text.
NotHaveError() Asserts that a Bad Request HTTP response content does not contain an error message identifiable by an expected field name and a wildcard error text.
HaveErrorMessage() Asserts that a Bad Request HTTP response content contains an error message identifiable by an wildcard error text.
Fine grained status assertions.
Should().Be1XXInformational() Asserts that a HTTP response has a HTTP status code representing an informational response.
Should().Be2XXSuccessful() Asserts that a HTTP response has a successful HTTP status code.
Should().Be4XXClientError() Asserts that a HTTP response has a HTTP status code representing a client error.
Should().Be3XXRedirection() Asserts that a HTTP response has a HTTP status code representing a redirection response.
Should().Be5XXServerError() Asserts that a HTTP response has a HTTP status code representing a server error.
Should().Be100Continue() Asserts that a HTTP response has the HTTP status 100 Continue
Should().Be101SwitchingProtocols() Asserts that a HTTP response has the HTTP status 101 Switching Protocols
Should().Be200Ok() Asserts that a HTTP response has the HTTP status 200 Ok
Should().Be201Created() Asserts that a HTTP response has the HTTP status 201 Created
Should().Be202Accepted() Asserts that a HTTP response has the HTTP status 202 Accepted
Should().Be203NonAuthoritativeInformation() Asserts that a HTTP response has the HTTP status 203 Non Authoritative Information
Should().Be204NoContent() Asserts that a HTTP response has the HTTP status 204 No Content
Should().Be205ResetContent() Asserts that a HTTP response has the HTTP status 205 Reset Content
Should().Be206PartialContent() Asserts that a HTTP response has the HTTP status 206 Partial Content
Should().Be300Ambiguous() Asserts that a HTTP response has the HTTP status 300 Ambiguous
Should().Be300MultipleChoices() Asserts that a HTTP response has the HTTP status 300 Multiple Choices
Should().Be301Moved() Asserts that a HTTP response has the HTTP status 301 Moved Permanently
Should().Be301MovedPermanently() Asserts that a HTTP response has the HTTP status 301 Moved Permanently
Should().Be302Found() Asserts that a HTTP response has the HTTP status 302 Found
Should().Be302Redirect() Asserts that a HTTP response has the HTTP status 302 Redirect
Should().Be303RedirectMethod() Asserts that a HTTP response has the HTTP status 303 Redirect Method
Should().Be303SeeOther() Asserts that a HTTP response has the HTTP status 303 See Other
Should().Be304NotModified() Asserts that a HTTP response has the HTTP status 304 Not Modified
Should().Be305UseProxy() Asserts that a HTTP response has the HTTP status 305 Use Proxy
Should().Be306Unused() Asserts that a HTTP response has the HTTP status 306 Unused
Should().Be307RedirectKeepVerb() Asserts that a HTTP response has the HTTP status 307 Redirect Keep Verb
Should().Be307TemporaryRedirect() Asserts that a HTTP response has the HTTP status 307 Temporary Redirect
Should().Be400BadRequest() Asserts that a HTTP response has the HTTP status 400 BadRequest
Should().Be401Unauthorized() Asserts that a HTTP response has the HTTP status 401 Unauthorized
Should().Be402PaymentRequired() Asserts that a HTTP response has the HTTP status 402 Payment Required
Should().Be403Forbidden() Asserts that a HTTP response has the HTTP status 403 Forbidden
Should().Be404NotFound() Asserts that a HTTP response has the HTTP status 404 Not Found
Should().Be405MethodNotAllowed() Asserts that a HTTP response has the HTTP status 405 Method Not Allowed
Should().Be406NotAcceptable() Asserts that a HTTP response has the HTTP status 406 Not Acceptable
Should().Be407ProxyAuthenticationRequired() Asserts that a HTTP response has the HTTP status 407 Proxy Authentication Required
Should().Be408RequestTimeout() Asserts that a HTTP response has the HTTP status 408 Request Timeout
Should().Be409Conflict() Asserts that a HTTP response has the HTTP status 409 Conflict
Should().Be410Gone() Asserts that a HTTP response has the HTTP status 410 Gone
Should().Be411LengthRequired() Asserts that a HTTP response has the HTTP status 411 Length Required
Should().Be412PreconditionFailed() Asserts that a HTTP response has the HTTP status 412 Precondition Failed
Should().Be413RequestEntityTooLarge() Asserts that a HTTP response has the HTTP status 413 Request Entity Too Large
Should().Be414RequestUriTooLong() Asserts that a HTTP response has the HTTP status 414 Request Uri Too Long
Should().Be415UnsupportedMediaType() Asserts that a HTTP response has the HTTP status 415 Unsupported Media Type
Should().Be416RequestedRangeNotSatisfiable() Asserts that a HTTP response has the HTTP status 416 Requested Range Not Satisfiable
Should().Be417ExpectationFailed() Asserts that a HTTP response has the HTTP status 417 Expectation Failed
Should().Be426UpgradeRequired() Asserts that a HTTP response has the HTTP status 426 UpgradeRequired
Should().Be500InternalServerError() Asserts that a HTTP response has the HTTP status 500 Internal Server Error
Should().Be501NotImplemented() Asserts that a HTTP response has the HTTP status 501 Not Implemented
Should().Be502BadGateway() Asserts that a HTTP response has the HTTP status 502 Bad Gateway
Should().Be503ServiceUnavailable() Asserts that a HTTP response has the HTTP status 503 Service Unavailable
Should().Be504GatewayTimeout() Asserts that a HTTP response has the HTTP status 504 Gateway Timeout
Should().Be505HttpVersionNotSupported() Asserts that a HTTP response has the HTTP status 505 Http Version Not Supported

The HttpResponsesMessage assertions from FluentAssertions vs. FluentAssertions.Web

In the 6.4.0 release the main library introduced a set of related assertions: BeSuccessful, BeRedirection, HaveClientError, HaveServerError, HaveError, HaveStatusCode, NotHaveStatusCode.

This library can still be used with FluentAssertions and it did not become obsoleted, not only because of the rich set of assertions, but also for the comprehensive output messages that are displayed when the test fails, feature that is not present in the main library, but in FluentAssertions.Web one.

FluentAssertions.Web vs FluentAssertions.Mvc vs FluentAssertions.Http

FluentAssertions.Web does not extend the ASP.NET Core Controllers assertions, if you are looking for that, then consider FluentAssertions.Mvc.

When FluentAssertions.Web was created, FluentAssertions.Http also existed at the time, solving the same problem when considering the asserting language. Besides the extra assertions added by FluentAssertions.Web, an important effort is put by this library on what happens when a test fails.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].