Fonlow.Testing.ServiceCore
3.6.1
See the version list below for details.
dotnet add package Fonlow.Testing.ServiceCore --version 3.6.1
NuGet\Install-Package Fonlow.Testing.ServiceCore -Version 3.6.1
<PackageReference Include="Fonlow.Testing.ServiceCore" Version="3.6.1" />
paket add Fonlow.Testing.ServiceCore --version 3.6.1
#r "nuget: Fonlow.Testing.ServiceCore, 3.6.1"
// Install Fonlow.Testing.ServiceCore as a Cake Addin #addin nuget:?package=Fonlow.Testing.ServiceCore&version=3.6.1 // Install Fonlow.Testing.ServiceCore as a Cake Tool #tool nuget:?package=Fonlow.Testing.ServiceCore&version=3.6.1
FonlowTesting
For the sake of CI, TDD, BDD, unit testing and integration testing, is it a CI server mandatory like TFS, TeamCity, Bamboo or Azure DevOps etc.?
Sometimes it could be handy and costing less to setup CI environment in each dev machine. Developers endorsing XP or TDD have been doing so for years before those off-the-shelf CI products were released to the market for team CI/CD.
A typical integration test suite should have the dependencies ready automatically before running. While a CI server generally has some built-in mechanism to launch respective dependencies and then run those test suites, it will be nicer that the integration test suite can take care of the dependencies at some degree, especially for those in-house service applications.
This project is to deliver some light-weight helper classes for developers to quickly construct integration tests on their own dev PC and share across dev team members. Even if your team is using a team CI/CD server, the helper classes may still help carrying out a lot integration tests before reaching the CI server. Also, if a test suite can take good care of setting up dependencies and tearing down them, the scripts/configuration on the team CI/CD server could be simplified, and the locked-in effect on a particular brand of team CI/CD product could be the least.
Remarks:
- A dedicated CI server generally provides comprehensive and powerful mechanisms of setting up and tearing down dependencies, like GitHub Actions/Workflows. This library will remain light-weight and serve as a complementary tool for overall CI.
NuGet Packages
For .NET Core 8.0 +
- Package Fonlow.Testing.ServiceCore
- Class ServiceCommandsFixture
- Package Fonlow.Testing.HttpCore
- Class BasicHttpClient
- Class HttpClientWithUsername
- Class TestingSettings
- Examples of Integration Test Suite
Examples
appsettings.json:
{
"Testing": {
"ServiceCommands": [
{
"CommandPath": "../../../../../PoemsMyDbCreator/bin/{BuildConfiguration}/net8.0/PoemsMyDbCreator.exe",
"Arguments": "Fonlow.EntityFrameworkCore.MySql \"server=localhost;port=3306;Uid=root; password=zzzzzzzz; database=Poems_Test; Persist Security Info=True;Allow User Variables=true\"",
"Delay": 0
},
{
"CommandPath": "dotnet",
"Arguments": "run --project ../../../../../PoetryApp/PoetryApp.csproj --no-build --configuration {BuildConfiguration}",
"BaseUrl": "http://localhost:5300/",
"Delay": 1
}
],
...
...
}
}
The setting will instruct the ServiceCommandsFixture as a collection fixture to use PoemsMyDbCreator.exe that will tear-down the DB and create a new one, then launch Web API PoetryApp that uses the blank new DB.
Remarks
- You may have an integration test suite that test the Data Access Layer based on Entity Framework (Core) or the Business Logic Layer using something similar to "PoemsMyDbCreator".
Integration Test Suite which is a client app to localhost:5300:
public class TestConstants
{
public const string LaunchWebApiAndInit = "LaunchWebApi";
}
[CollectionDefinition(TestConstants.LaunchWebApiAndInit)]
public class DotNetHostCollection : ICollectionFixture<Fonlow.Testing.ServiceCommandsFixture>
{
}
public class PoemsFixture : AuthHttpClientWithUsername
{
public PoemsFixture()
{
System.Text.Json.JsonSerializerOptions jsonSerializerSettings = new System.Text.Json.JsonSerializerOptions()
{
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,
PropertyNameCaseInsensitive = true,
};
Api = new PoemsApp.Controllers.Client.Poems(AuthorizedClient, jsonSerializerSettings);
TagsApi = new PoemsApp.Controllers.Client.Tags(AuthorizedClient, jsonSerializerSettings);
}
public PoemsApp.Controllers.Client.Poems Api { get; private set; }
public PoemsApp.Controllers.Client.Tags TagsApi { get; private set; }
}
[Collection(TestConstants.LaunchWebApiAndInit)]
public class PoemsTests : IClassFixture<PoemsFixture>
{
public PoemsTests(PoemsFixture fixture)
{
api = fixture.Api;
tagsApi = fixture.TagsApi;
authorizedClient = fixture.AuthorizedClient;
}
readonly PoemsApp.Controllers.Client.Poems api;
readonly PoemsApp.Controllers.Client.Tags tagsApi;
readonly HttpClient authorizedClient;
[Fact]
public async Task TestAddPoemAndUpdatePublished()
{
var p = await api.AddAsync(new Poem
{
"ServiceCommandsFixture" will replace {BuildConfiguration} with the build configuration of the test suite.
Alternative, you may have "appsettings.Debug.json", "appsettings.Release.json" or even something like "appsettings.MacRelease.json" together with "appsettings.json".
appsettings.Debug.json:
{
"Testing": {
"ServiceCommands": [
{
"CommandPath": "dotnet",
"Arguments": "run --project ../../../../../DemoCoreWeb/DemoCoreWeb.csproj --no-build --configuration Debug",
"BaseUrl": "http://127.0.0.1:5000/",
"Delay": 2
}
]
}
}
Settings
public sealed class TestingSettings
{
public string Username { get; set; }
public string Password { get; set; }
/// <summary>
/// For testing with many different user credentials.
/// </summary>
public UsernamePassword[] Users { get; set; }
public ServiceCommand[] ServiceCommands { get; set; }
/// <summary>
/// Build configuration such as Debug, Release or whatever custom build configuration.
/// ServiceCommandFixture will replace {BuildConfiguration} in arguments with this.
/// </summary>
public string BuildConfiguration { get; private set; }
}
public sealed class UsernamePassword
{
public string Username { get; set; }
public string Password { get; set; }
}
public sealed class ServiceCommand
{
public string CommandPath { get; set; }
public string Arguments { get; set; }
/// <summary>
/// Some services may take some seconds to launch then listen, especially in GitHub Actions which VM/container could be slow. A good bet may be 5 seconds.
/// </summary>
public int Delay { get; set; }
public string ConnectionString { get; set; }
public string BaseUrl { get; set; }
}
More Examples of Launching Services/Commands
In-house Web API
{
"CommandPath": "dotnet",
"Arguments": "run --project ../../../../../DemoCoreWeb/DemoCoreWeb.csproj --no-build --configuration {BuildConfiguration}",
}
Hints:
- The current directory of the launched Web API is the directory containing the csproj file.
{
"CommandPath": "dotnet",
"Arguments": "../../../../../DemoCoreWeb/bin/{BuildConfiguration}/net8.0/DemoCoreWeb.dll",
}
Hints:
- The current directory of the launched Web API is the directory of the test suite. Thus if some features of Web API depends on the locations of current directory, content root path and Web root path, such launch may result in problems, for example, it cannot find some files in some default relative locations.
{
"CommandPath": "../../../../../DemoCoreWeb/bin/{BuildConfiguration}/net8.0/DemoCoreWeb.exe",
}
Hints:
- The current directory of the launched Web API is the directory of the EXE file. And this is recommended.
- The only setback comparing with launching through the csproj file is that after upgrading to next .NET version, you need to adjust the .NET version in the path, for example, from "net8.0" to "net9.0" and so on.
GitHub Workflow
For .NET developers, GitHub actions provides a "dotnet.yml" which by default run the debug build. Sometimes it may be more appropriate to run release build. Therefore, change the last 2 steps, like:
- name: Build
run: dotnet build --no-restore --configuration Release
- name: Test
run: dotnet test --no-build --verbosity normal --configuration Release
And name the file as "dotnetRelease.yml".
If the integration test suites depend on relatively simple "out-of-process" resources such as ASP.NET Core Web services, the helper classes of "Fonlow.Testing.ServiceCore" could be simple and handy enough before you need to craft more complex GitHub workflows.
Examples:
- https://github.com/zijianhuang/webapiclientgen/actions
- https://github.com/zijianhuang/openapiclientgen/actions
Alternatives
The libraries of helper classes have been developed since the .NET Framework era. These days since .NET Core, there have been more well designed libraries around:
- Functional Testing ASP.NET Core Apps
- Docker Compose Fixture
- Integration Test with .Net Core and Docker
- BenchmarkDotNet
References:
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net8.0
- Fonlow.Testing.HttpCore (>= 3.4.1)
- Microsoft.Extensions.Configuration.Json (>= 8.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Fonlow.Testing.ServiceCore:
Package | Downloads |
---|---|
Fonlow.Testing.Integration
Utilities and fixtures for integration testing with xUnit |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
3.8.0 | 272 | 7/1/2024 |
3.8.0-Alpha2 | 101 | 6/29/2024 |
3.8.0-Alpha | 93 | 6/29/2024 |
3.7.0 | 128 | 6/27/2024 |
3.7.0-Alpha2 | 91 | 6/26/2024 |
3.7.0-Alpha | 91 | 6/25/2024 |
3.6.4-Beta4 | 94 | 6/25/2024 |
3.6.4-Beta3 | 90 | 6/25/2024 |
3.6.2 | 162 | 6/17/2024 |
3.6.1 | 105 | 6/16/2024 |
3.6.0 | 104 | 6/16/2024 |
3.5.0 | 577 | 6/8/2024 |
3.4.1 | 460 | 6/1/2024 |
3.4.0 | 107 | 6/1/2024 |
3.3.0 | 172 | 5/16/2024 |
3.2.1 | 414 | 3/30/2024 |
3.2.0 | 106 | 3/30/2024 |
3.1.0 | 272 | 11/23/2023 |
3.0.2 | 390 | 1/26/2023 |
3.0.1 | 301 | 1/26/2023 |
3.0.0 | 294 | 1/26/2023 |
2.0.0 | 577 | 6/30/2021 |
1.0.2 | 719 | 12/3/2019 |
1.0.1 | 504 | 12/2/2019 |
1.0.0 | 513 | 11/18/2019 |
upgraded to .NET 8. Linux and Github Actions friendly.