Fonlow.Testing.ServiceCore 3.7.0-Alpha

This is a prerelease version of Fonlow.Testing.ServiceCore.
There is a newer version of this package available.
See the version list below for details.
dotnet add package Fonlow.Testing.ServiceCore --version 3.7.0-Alpha                
NuGet\Install-Package Fonlow.Testing.ServiceCore -Version 3.7.0-Alpha                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Fonlow.Testing.ServiceCore" Version="3.7.0-Alpha" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Fonlow.Testing.ServiceCore --version 3.7.0-Alpha                
#r "nuget: Fonlow.Testing.ServiceCore, 3.7.0-Alpha"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Fonlow.Testing.ServiceCore as a Cake Addin
#addin nuget:?package=Fonlow.Testing.ServiceCore&version=3.7.0-Alpha&prerelease

// Install Fonlow.Testing.ServiceCore as a Cake Tool
#tool nuget:?package=Fonlow.Testing.ServiceCore&version=3.7.0-Alpha&prerelease                

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 +

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{ExecutableExt}",
}

Hints:

  • The current directory of the launched Web API is the directory of the EXE file. And this is recommended. On MacOs and Linux, the extension name of executable files is empty, while on Windows, it is ".exe".
  • 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:

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:

References:

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.9.0 40 11/21/2024
3.8.0 283 7/1/2024
3.8.0-Alpha2 102 6/29/2024
3.8.0-Alpha 94 6/29/2024
3.7.0 129 6/27/2024
3.7.0-Alpha2 92 6/26/2024
3.7.0-Alpha 92 6/25/2024
3.6.4-Beta4 95 6/25/2024
3.6.4-Beta3 91 6/25/2024
3.6.2 163 6/17/2024
3.6.1 106 6/16/2024
3.6.0 105 6/16/2024
3.5.0 578 6/8/2024
3.4.1 461 6/1/2024
3.4.0 108 6/1/2024
3.3.0 173 5/16/2024
3.2.1 415 3/30/2024
3.2.0 107 3/30/2024
3.1.0 273 11/23/2023
3.0.2 391 1/26/2023
3.0.1 304 1/26/2023
3.0.0 295 1/26/2023
2.0.0 578 6/30/2021
1.0.2 720 12/3/2019
1.0.1 505 12/2/2019
1.0.0 514 11/18/2019

upgraded to .NET 8. Linux and Github Actions friendly.