Skip to content

Commit

Permalink
develop into master (#90)
Browse files Browse the repository at this point in the history
* Create get request when it has an object with some list

* DateTime as a primitive type but using custom formatter (#81)

* Fixing codeQL alerts (#82)

* feature: Get url (#83)

* In IncludeContentAsFormUrlEncoded and PrimitiveParameterActionTokenizer explicit conversion for floats (#84)

Create random ParamWithSeveralTypes
More tests

* Add new CreateHttpApiRequest with TActionResponse (#85)

Fix CodeQL alerts
Test

* Add net7.0 Target Version (#86)

* Add net7.0 Target Version
Update nugets

* add net 7 in workflows

* update global.json

* remove extra builds ci.yml

* ReadContentAsAsync allows string type (#87)

Tests for HttpResponseMessageExtensions

* Allow send a IFormFile (#88)

* Allow IFormFile
Refactor IncludeContentAsFormUrlEncoded
Remove Newtonsoft.Json dependecy

* Update documentation

* Refactor GivenFile

* Update version to 3.5.0 (#89)

* Add DateTimeOffset to IsDateTime function (#91)

Move TypeExtensions
  • Loading branch information
Sergio1192 authored May 25, 2023
1 parent b000e95 commit fde4f8e
Show file tree
Hide file tree
Showing 38 changed files with 2,949 additions and 2,402 deletions.
9 changes: 3 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,10 @@ jobs:
3.1.417
5.0.101
6.0.300
7.0.302
- name: Build .NET 3.1
run: dotnet build -c $BUILD_CONFIG --framework netcoreapp3.1
- name: Build .NET 5.0
run: dotnet build -c $BUILD_CONFIG --framework net5.0
- name: Build .NET 6.0
run: dotnet build -c $BUILD_CONFIG --framework net6.0
- name: Build
run: dotnet build -c $BUILD_CONFIG

- name: Test
run: dotnet test -c $BUILD_CONFIG --no-build
2 changes: 1 addition & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: "CodeQL"

on:
push:
branches: [ "master" ]
branches: [ "master", "develop" ]
pull_request:
branches: [ "master", "develop" ]
workflow_dispatch:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/nuget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ jobs:
3.1.417
5.0.101
6.0.300
7.0.302
- name: Build
run: dotnet build -c $BUILD_CONFIG
Expand Down
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<Project>
<PropertyGroup Label="SDK Versions">
<NetCoreTargetVersion>netcoreapp3.1;net5.0;net6.0</NetCoreTargetVersion>
<NetCoreTargetVersion>netcoreapp3.1;net5.0;net6.0;net7.0</NetCoreTargetVersion>
<LangVersion>latest</LangVersion>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>

<PropertyGroup Label="Package information">
<Version>3.4.0</Version>
<Version>3.5.0</Version>

<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>http://github.com/xabaril/Acheve.TestHost</PackageProjectUrl>
Expand Down
63 changes: 30 additions & 33 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,35 +1,32 @@
<Project>
<PropertyGroup Label=".Net version" Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
<NetCoreVersion>3.1.25</NetCoreVersion>
</PropertyGroup>

<PropertyGroup Label=".Net version" Condition=" '$(TargetFramework)' == 'net5.0' ">
<NetCoreVersion>5.0.17</NetCoreVersion>
</PropertyGroup>

<PropertyGroup Label=".Net version" Condition=" '$(TargetFramework)' == 'net6.0' ">
<NetCoreVersion>6.0.5</NetCoreVersion>
</PropertyGroup>

<ItemGroup Label="General Dependencies">
<PackageVersion Include="Newtonsoft.Json" Version="13.0.1" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="$(NetCoreVersion)" />
</ItemGroup>

<ItemGroup Label="Sample Dependencies">
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(NetCoreVersion)" />
</ItemGroup>

<ItemGroup Label="Testing Dependencies">
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="$(NetCoreVersion)" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageVersion Include="FluentAssertions" Version="6.7.0" />
<PackageVersion Include="xunit" Version="2.4.1" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.4.5" />
<PackageVersion Include="coverlet.collector" Version="3.1.2" />
</ItemGroup>

<ItemGroup Label="Github Dependencies">
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" />
</ItemGroup>
<PropertyGroup Label=".Net version" Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
<NetCoreVersion>3.1.32</NetCoreVersion>
</PropertyGroup>
<PropertyGroup Label=".Net version" Condition=" '$(TargetFramework)' == 'net5.0' ">
<NetCoreVersion>5.0.17</NetCoreVersion>
</PropertyGroup>
<PropertyGroup Label=".Net version" Condition=" '$(TargetFramework)' == 'net6.0' ">
<NetCoreVersion>6.0.16</NetCoreVersion>
</PropertyGroup>
<PropertyGroup Label=".Net version" Condition=" '$(TargetFramework)' == 'net7.0' ">
<NetCoreVersion>7.0.5</NetCoreVersion>
</PropertyGroup>
<ItemGroup Label="General Dependencies">
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="$(NetCoreVersion)" />
</ItemGroup>
<ItemGroup Label="Sample Dependencies">
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(NetCoreVersion)" />
</ItemGroup>
<ItemGroup Label="Testing Dependencies">
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="$(NetCoreVersion)" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageVersion Include="FluentAssertions" Version="6.11.0" />
<PackageVersion Include="xunit" Version="2.4.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.4.5" />
<PackageVersion Include="coverlet.collector" Version="3.2.0" />
</ItemGroup>
<ItemGroup Label="Github Dependencies">
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" />
</ItemGroup>
</Project>
78 changes: 46 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

[![Build status](https://github.com/Xabaril/Acheve.TestHost/actions/workflows/nuget.yml/badge.svg)](https://github.com/Xabaril/Acheve.TestHost/actions/workflows/nuget.yml/badge.svg) [![NuGet](https://img.shields.io/nuget/v/acheve.testhost.svg)](https://www.nuget.org/packages/acheve.testhost/)

NuGet package to improve AspNetCore TestServer experiences
NuGet package to improve AspNetCore TestServer experiences

Unit testing your Mvc controllers is not enough to verify the correctness of your WebApi. Are the filters working? Is the correct status code sent when that condition is reached? Is the user authorized to request that endpoint?

The NuGet package [Microsoft.AspNetCore.TestHost](https://www.nuget.org/packages/Microsoft.AspNetCore.TestHost/) allows you to create an in memory server that exposes an HttpClient to be able to send request to the server. All in memory, all in the same process. Fast. It's the best way to create integration tests in your Mvc application. But at this moment this library has some gaps that *Acheve* try to fill.
The NuGet package [Microsoft.AspNetCore.TestHost](https://www.nuget.org/packages/Microsoft.AspNetCore.TestHost/) allows you to create an in memory server that exposes an HttpClient to be able to send request to the server. All in memory, all in the same process. Fast. It's the best way to create integration tests in your Mvc application. But at this moment this library has some gaps that _Acheve_ try to fill.

## Get started

Expand Down Expand Up @@ -66,29 +66,29 @@ the claims for authenticated calls to the WebApi.

In the TestServer startup class you shoud incude the authentication service and add the .Net Core new AUthentication middleware:

```csharp
public class TestStartup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultScheme = TestServerDefaults.AuthenticationScheme;
})
.AddTestServer();

var mvcCoreBuilder = services.AddMvcCore();
ApiConfiguration.ConfigureCoreMvc(mvcCoreBuilder);
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app)
{
app.UseAuthentication();

app.UseMvcWithDefaultRoute();
}
}
```csharp
public class TestStartup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultScheme = TestServerDefaults.AuthenticationScheme;
})
.AddTestServer();

var mvcCoreBuilder = services.AddMvcCore();
ApiConfiguration.ConfigureCoreMvc(mvcCoreBuilder);
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app)
{
app.UseAuthentication();

app.UseMvcWithDefaultRoute();
}
}
```

And in your tests you can use an HttpClient with default credentials or build
Expand Down Expand Up @@ -178,7 +178,7 @@ var response = await _server.CreateRequest("api/values/public")
In general, in our tests a new simple API class is created to hide this uri and improve the code.

```csharp
// some code on tests
// some code on tests
var response = await _server.CreateRequest(Api.Values.Public)
.GetAsync();
Expand All @@ -199,7 +199,7 @@ The main problems on this approach are:
1. If any route convention is changed all integration test will fail.
1. If you refactor any parameter order the integration test will fail.

With *Acheve* you can create the uri dynamically using the attribute routing directly from your controllers.
With _Acheve_ you can create the uri dynamically using the attribute routing directly from your controllers.

```csharp
var response = await _server.CreateHttpApiRequest<ValuesController>(controller=>controller.PublicValues())
Expand All @@ -208,7 +208,7 @@ var response = await _server.CreateHttpApiRequest<ValuesController>(controller=>

## About adding extra query parameters

The package has a *RequestBuilder* extension to add a new query parameter: *AddQueryParameter*.
The package has a _RequestBuilder_ extension to add a new query parameter: _AddQueryParameter_.

```csharp
[Fact]
Expand All @@ -221,9 +221,9 @@ public async Task MyFirstTest()
}
```

## About removin query parameters
## About removing query parameters

The package has a *RequestBuilder* extension to remove a query parameter: *RemoveQueryParameter*.
The package has a _RequestBuilder_ extension to remove a query parameter: _RemoveQueryParameter_.

```csharp
[Fact]
Expand All @@ -236,12 +236,26 @@ public async Task MyFirstTest()
}
```

## About sending files

The package has a _TestServer_ extension to get a test file: _GivenFile_.

```csharp
[Fact]
public async Task MyFirstTest()
{
...
var file = server.GivenFile();
...
}
```

## Improving assertions in API responses

The package has HttpResponseMessage extension to help us assert the response.

- *IsSuccessStatusCodeOrThrow*: Throw exception with the response content in the message.
- *ReadContentAsAsync*: Read the response content and cast it.
- _IsSuccessStatusCodeOrThrow_: Throw exception with the response content in the message.
- _ReadContentAsAsync_: Read the response content and cast it.

```csharp
[Fact]
Expand Down
6 changes: 3 additions & 3 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"projects": [ "src", "test", "samples" ],
"projects": ["src", "test", "samples"],
"sdk": {
"version": "6.0.300",
"version": "6.0.000",
"rollForward": "latestMajor"
}
}
}
6 changes: 0 additions & 6 deletions src/Acheve.TestHost/Acheve.TestHost.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,13 @@
<PropertyGroup>
<TargetFrameworks>$(NetCoreTargetVersion)</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
<Folder Include="Routing\AttributeTemplates\" />
<Folder Include="Routing\Tokenizers\" />
</ItemGroup>

<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.TestHost" />
<PackageReference Include="Newtonsoft.Json" />
</ItemGroup>

</Project>
File renamed without changes.
47 changes: 47 additions & 0 deletions src/Acheve.TestHost/Extensions/HttpResponseMessageExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System.Text.Json;
using System.Threading.Tasks;

namespace System.Net.Http;

public static class HttpResponseMessageExtensions
{
/// <summary>
/// Try to extract the error message in the response content in case the response status code is not success.
/// </summary>
/// <param name="response">The HttpResponseMessage instance</param>
/// <returns></returns>
public static async Task IsSuccessStatusCodeOrThrow(this HttpResponseMessage response)
{
if (response.IsSuccessStatusCode)
{
return;
}

var content = await response.Content.ReadAsStringAsync();

throw new Exception($"Response status does not indicate success: {response.StatusCode:D} ({response.StatusCode}); \r\n{content}");
}

/// <summary>
/// Read HttpResponseMessage and convert to T Class
/// </summary>
/// <typeparam name="T">Class type or primitive type</typeparam>
/// <param name="responseMessage">The HttpResponseMessage instance</param>
/// <returns>T class object</returns>
public static async Task<T> ReadContentAsAsync<T>(this HttpResponseMessage responseMessage)
{
var content = await responseMessage.Content.ReadAsStringAsync();

if (typeof(T) == typeof(string))
{
content = $"\"{content}\"";
}

var json = JsonSerializer.Deserialize<T>(content, new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true
});

return json;
}
}
Loading

0 comments on commit fde4f8e

Please sign in to comment.