Coder Social home page Coder Social logo

adrianiftode / fluentassertions.web Goto Github PK

View Code? Open in Web Editor NEW
104.0 104.0 6.0 991 KB

FluentAssertions for HTTP APIs

License: Apache License 2.0

C# 100.00%
asp-net-core c-sharp fluentassertions functional-testing netcore testserver unit-testing

fluentassertions.web's People

Contributors

adrianiftode avatar aiftodesage avatar sdamian avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

fluentassertions.web's Issues

Typo during BeAs assertion

Instead of Expected response to have a content equivalent to a model, but is has differences: it should be , but it is has

Showing binary requests in test logs causes issues in Visual Studio

Firstly, thanks for your work on the library - has made testing web APIs very easy.

I've encountered an issue with logs when sending binary requests. I'm testing an image upload endpoint and in my test I'm uploading a high resolution jpg file which is 900kb (testing that the server downscales large images to a specified max resolution correctly and such before storing the file).

When the test passes everything is good, but if it fails,

  1. the test log tries to show the binary as text and produces weird characters, eventually truncates the body in the log - this one doesn't bother me, although I don't know what potential issues there are in trying to display binary as text
  2. the real issue is when you try to view the test explorer panel in Visual Studio, Visual Studio becomes unresponsive - for 20 sec or so - until I guess it gives up on showing the tree of tests. It'll draw all the tests in the list up until the failed test. At that point, the status icon next to the failed test, and everything that should appear below that test (i.e. other tests), aren't drawn.

image

And VS as a whole is largely unusable unless you change the panel to something other than the test explorer.

If you go to a test in code, click on "Show in test explorer", then wait out the 20+ sec, it then becomes possible to read the log message (as per my point 1) to try to resolve it to get the test to pass. But yeah - if the log can be improved to not show binary data or perhaps show it as a hex string, this might help the problem, or perhaps it's to do with how it tries to find the point to truncate the body that has an issue when reading binary.

I have attached a sample project which reproduces the issue. If you go into the test project, under /Controllers/MyApiControllerTests.cs, the first test should return 200 OK but I've made the test assert for 400 bad request just to force the test to fail - you can comment this and uncomment the check for 200 OK to get the test to pass. I also added a 2nd test just to demonstrate that VS stops drawing tests below as per screenshot above, but I realise this is to do with the VS GUI and not the library.

TestAPIWithBinary.zip

Let me know if there is any more information I can provide.

Improve the error message when a header value does not match the assertion

In this example, the header actually exists, but the error message suggests it doesn't. A better message would express the fact the value differs.

Expected value to contain the HTTP header "Location" having value "/api/iab/optout", but no such header was found in the actual response. 
 
 The HTTP response was:

HTTP/1.1 302 Redirect
Vary: Cookie
Location: /api/iab/status
Set-Cookie: XSRF-TOKEN=Fpxq1CaquEChrslAeZ37TAa; path=/
Content-Length: 0

***** Content is of a stream type having the length 0. *****

The originated HTTP request was:

GET https://.../api/iab/coop?action=3 HTTP 2.0
Cookie: 
Content-Length: 0

Be200Ok fails to show the correct message when the response has no content type

Given a test using the following snippet

            // Act
            var  response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
            {
                Content = new StringContent("", Encoding.UTF8)
            };
            response.Content.Headers.ContentType = null;

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

When it is run
Then the expected behavior is to fail with the following message

Message: 
    Expected HTTP response to be "OK", but found Unauthorized.
    
    The HTTP response was:
    
    HTTP/1.1 401 Unauthorized
    Content-Length: 0
    
    
    The originated HTTP request was <null>.

But the actual behavior is it fails with the following message

```Message: 
    System.NullReferenceException : Object reference not set to an instance of an object.
  Stack Trace: 
    JsonProcessor.CanHandle()
    JsonProcessor.GetContentInfo(StringBuilder contentBuilder)
    HttpResponseMessageFormatter.RunProcessors(IContentProcessor[] processors)
    HttpResponseMessageFormatter.AppendResponseContent(StringBuilder messageBuilder, HttpResponseMessage response)
    HttpResponseMessageFormatter.AppendResponse(StringBuilder messageBuilder, HttpResponseMessage response)
    HttpResponseMessageFormatter.AppendHttpResponseMessage(StringBuilder messageBuilder, HttpResponseMessage response)
    <<Format>b__0>d.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
    HttpResponseMessageFormatter.Format(Object value, FormattingContext context, FormatChild formatChild)
    Formatter.ToString(Object value, Boolean useLineBreaks) line 97
    SelectArrayIterator`2.ToArray()
    Enumerable.ToArray[TSource](IEnumerable`1 source)
    MessageBuilder.FormatArgumentPlaceholders(String failureMessage, Object[] failureArgs) line 91
    MessageBuilder.Build(String message, Object[] messageArgs, String reason, ContextDataItems contextData, String identifier, String fallbackIdentifier) line 36
    <>c__DisplayClass30_0.<FailWith>b__0() line 199
    AssertionScope.FailWith(Func`1 failReasonFunc) line 216
    HttpResponseMessageAssertions.ExecuteStatusAssertion(String because, Object[] becauseArgs, HttpStatusCode expected, String otherName)
    HttpResponseMessageAssertions.Be200Ok(String because, Object[] becauseArgs)
    TestCasesTests.Get_TestCases_ShouldBeOk() line 39
    --- End of stack trace from previous location where exception was thrown ---

Does not work with FluentAssertions 6.4.0

After FluentAssertions 6.4.0 release where fluentassertions/fluentassertions#1737 was merged, this library now conflicts with the main one, so I have a bunch of errors like

OrderTests.cs(45,18): error CS0121: The call is ambiguous between the following methods or properties: 'FluentAssertions.AssertionExtensions.Should(System.Net.Http.HttpResponseMessage)' and 'FluentAssertions.HttpResponseMessageFluentAssertionsExtensions.Should(System.Net.Http.HttpResponseMessage?)'

I have no idea how I can resolve this manually.

Do you know a way to use the latest FluentAssertions and FluentAssertions.Web?

Asserting an HttpResponseMessage to HaveContent throws an exception when the response is InternalServerError

Steps

 response.Should().Be500InternalServerError()
                .And.HaveContent("An account with email `xxx` already exists");

Expected

The test to pass or the test to fails with the correct assertions messages

Actual outcome

 Message: 
    Newtonsoft.Json.JsonReaderException : Unexpected character encountered while parsing value: <. Path '', line 1, position 1.
  Stack Trace: 
    JsonTextReader.ReadStringValue(ReadType readType)
    JsonTextReader.ReadAsString()
    JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)
    JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
    JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
    JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
    JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
    HttpContentExtensions.ReadAsAsync[T](HttpContent content)
    HttpResponseMessageAssertions.GetSubjectModel[TModel]()
    HttpResponseMessageAssertions.HaveContent[TModel](TModel expectedModel, String because, Object[] becauseArgs)
    UsersControllerTests.Post_ReturnsServerError_WhenUserDoesNotExist_ButAPhantomAccountDoes() line 80
    --- End of stack trace from previous location where exception was thrown ---

Add a MatchLocation and/or HaveLocation extension for redirect responses

Currently to check that redirect response that has the expected redirect location something like the following is tried:

response.Should().Be302Redirect()
                .And.HaveHeader("Location")
                .And.Match("/redirect-location");

What could ease would be:

to assert an exact match of the redirect header

response.Should().Be302Redirect()
                .And.HaveLocation("/redirect-location?id=231");

or to have a wild card match

response.Should().Be302Redirect()
                .And.MatchLocation("/redirect-location");

Deserialization when the response is an array, but the expected model is a single object

The expected model was a single object, and the response an array.

Expected response to have a content equivalent to a model of type "<>f__AnonymousType0`7[System.Int32,System.String,System.String,System.Int32,System.DateTime,System.Int32,System.Int32]", but the JSON representation could not be parsed, as the operation failed with the following message: "Exception while deserializing the model with SystemTextJsonSerializer: The JSON value could not be converted to <>f__AnonymousType0`7[System.Int32,System.String,System.String,System.Int32,System.DateTime,System.Int32,System.Int32]. Path: $ | LineNumber: 0 | BytePositionInLine: 1.". 

The HTTP response was:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 2025


***** Content is too large to display and only a part is printed. *****
[{"id":"03e9bf9d-5fec-4cdc-82a3-19c5fa1c847e","userName":"Utility",

Warnings related to STEW conflicts when building for .NET 5.0

C:\Program Files\dotnet\sdk\7.0.100\Microsoft.Common.CurrentVersion.targets(2352,5): warning MSB3277: Found conflicts between different versions of "System.T ext.Encodings.Web" that could not be resolved. [D:\adrian\opensource\FluentAssertions.Web\test\FluentAssertions.Web.FluentAssertionsWebConfig.Tests\FluentAss ertions.Web.FluentAssertionsWebConfig.Tests.csproj::TargetFramework=net5.0]
C:\Program Files\dotnet\sdk\7.0.100\Microsoft.Common.CurrentVersion.targets(2352,5): warning MSB3277: There was a conflict between "System.Text.Encodings.Web , Version=5.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" and "System.Text.Encodings.Web, Version=5.0.0.1, Culture=neutral, PublicKeyToken=cc7b13f fcd2ddd51". [D:\adrian\opensource\FluentAssertions.Web\test\FluentAssertions.Web.FluentAssertionsWebConfig.Tests\FluentAssertions.Web.FluentAssertionsWebConf ig.Tests.csproj::TargetFramework=net5.0]

Multiple headers with the same header name should be printed line by line and not joined by comma

Context: a response having multiple Set-Cookie headers

Actual

   The HTTP response was:
   
   HTTP/1.1 200 OK
   Vary: Cookie
   Set-Cookie: uid=6cfdfc78-2200-4f7b-9c19-c38b379156a8; expires=Tue, 19 Apr 2022 18:42:10 GMT; path=/, XSRF-TOKEN=7d25c15c-c116-4859-9d2b-ecc13a032214; path=/
   Content-Length: 0
   
   ***** Content is of a stream type having the length 0. *****
   
   The originated HTTP request was:

Expected

   The HTTP response was:
   
   HTTP/1.1 200 OK
   Vary: Cookie
   Set-Cookie: uid=6cfdfc78-2200-4f7b-9c19-c38b379156a8; expires=Tue, 19 Apr 2022 18:42:10 GMT; path=/
   Set-Cookie:  XSRF-TOKEN=7d25c15c-c116-4859-9d2b-ecc13a032214; path=/
   Content-Length: 0
   
   ***** Content is of a stream type having the length 0. *****
   
   The originated HTTP request was:

Configurable delegate to allow post-formatting the response

Use case:

Consider the following response:

Expected HTTP response to be "OK", but found InternalServerError.
    
    The HTTP response was:
    
    HTTP/1.1 500 InternalServerError
    Set-Cookie: XSRF-TOKEN=aaaaaaaaaaaaaaaaaaaaaaa; path=/
    Content-Type: application/json
    Content-Length: 3963
    
    {
        "traceId": "traceba9919c5493c503a",
        "message": "An error has occurred.",
        "exceptionMessage": "Object reference not set to an instance of an object.",
        "exceptionType": "NullReferenceException",
        "stackTrace": "    at SomeClass.SomeMethod() in C:\\dev\\Tracker.cs:line 111\r\n     at SomeMethod() in C:\\dev\\workspace\\Someclasss.cs:line 43"
    }
    The originated HTTP request was:

The stacktrace property is not easily readable as it is formatted as a one-line string. Would be useful to intercept the response and replace "\r\n" with the actual new lines.

So an expected output would be

Expected HTTP response to be "OK", but found InternalServerError.
    
    The HTTP response was:
    
    HTTP/1.1 500 InternalServerError
    Set-Cookie: XSRF-TOKEN=aaaaaaaaaaaaaaaaaaaaaaa; path=/
    Content-Type: application/json
    Content-Length: 3963
    
    {
        "traceId": "traceba9919c5493c503a",
        "message": "An error has occurred.",
        "exceptionMessage": "Object reference not set to an instance of an object.",
        "exceptionType": "NullReferenceException",
        "stackTrace": "   at SomeClass.SomeMethod() in C:\\dev\\Tracker.cs:line 111
     at SomeMethod() in C:\\dev\\workspace\\Someclasss.cs:line 43"
    }
    The originated HTTP request was:

And thus would ease reading the stack trace

Update packages references

Could you please update the references to 3rd party packages? Currently those old package versions are either vulnerable/deprecated themselves or bring in some other transient dependencies which are vulnerable/deprecated.

  • System.Text.Json 5.0.2 is deprecated
  • Microsoft.AspNet.WebApi.Client 5.2.4 -> Newtonsoft.Json.Bson 1.0.1 -> NETStandard.Library 1.6.1 -> multiple vulnerable packages

Output for a new xUnit test project with FluentAssertions.Web:

> dotnet list package --include-transitive --vulnerable
   Transitive Package                    Resolved   Severity   Advisory URL
   > System.Net.Http                     4.3.0      High       https://github.com/advisories/GHSA-7jgj-8wvc-jh57
   > System.Text.RegularExpressions      4.3.0      High       https://github.com/advisories/GHSA-cmhx-cq75-c4mj

> dotnet list package --include-transitive --deprecated
   Transitive Package      Resolved   Reason(s)      Alternative
   > System.Text.Json      5.0.2      Other,Legacy

Large JSON responses are not truncated as beautified

Actual

The HTTP response was:

HTTP/1.1 200 OK
Request-Context: appId=
Content-Type: application/json; charset=utf-8
Content-Length: 527079


***** Content is too large to display and only a part is printed. *****
{"consumption":[{"datetime":"2022-06-21T13:00:00","consumption":43.66},{"datetime":"2022-06-21T14:00:00","consumpti

Expected

The HTTP response was:

HTTP/1.1 200 OK
Request-Context: appId=
Content-Type: application/json; charset=utf-8
Content-Length: 1135

{
  "consumption": [
    {
      "datetime": "2022-06-21T13:00:00",
      "consumption": 43.66
    },

Add changelog

I am always wary of updating packages if I don't know what's changed. I suggest adding a changelog to this repo, that contains at least the changes in 1.2.5.

For a suggested changelog format, see Keep a changelog. The most important part, however, is simply having a list of changes.

Remove expectedWildcardErrorMessage from HaveError

Given a BadRequest response, might be more readable to Assert error messages with more affinity

So an alternative API to

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

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

	// Assert
	response.Should().Be400BadRequest()
		.And.HaveError("Author", "The Author field is required.")
		.And.HaveError("Content", "The Content field is required.");
}

Would be

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

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

	// Assert
	response.Should().Be400BadRequest()
		.And.HaveError("Author").And.HaveErrorMessage( "The Author field is required.")
                .And.HaveError("Content").And.HaveErrorMessage("The Content field is required.");
}

or

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

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

	// Assert
	response.Should().Be400BadRequest()
		.And.HaveError("Author").Which.ErrorMessage.Should().Be( "The Author field is required.")
                .And.HaveError("Content").Which.ErrorMessage.Should().Be("The Content field is required.");
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.