From 49e8b3cb4bb66dfcff3fa427a35c4dade7502ef6 Mon Sep 17 00:00:00 2001 From: zijianhuang Date: Sun, 16 Jun 2024 17:56:22 +1000 Subject: [PATCH] v3.6 released --- .github/workflows/dotnetRelease.yml | 4 - DemoCoreWeb/DemoCoreWeb.csproj | 2 +- DotNetPack.ps1 | 2 +- Fonlow.Testing.HttpCore/AuthHttpClients.cs | 1 + Fonlow.Testing.HttpCore/DefaultHttpClient.cs | 1 + .../DefaultHttpClientWithUsername.cs | 1 + .../Fonlow.Testing.HttpCore.csproj | 68 ++++---- .../HttpClientWithUsername.cs | 5 +- Fonlow.Testing.HttpCore/README.md | 5 - Fonlow.Testing.HttpCore/TestingSettings.cs | 51 +++++- .../DeploymentItemFixture.cs | 4 + Fonlow.Testing.ServiceCore/DirFunctions.cs | 56 +++--- .../Fonlow.Testing.ServiceCore.csproj | 2 +- Fonlow.Testing.ServiceCore/IisExpressAgent.cs | 32 ++-- .../IisExpressAgentBase.cs | 12 +- .../IisExpressFixture.cs | 26 +-- .../IisExpressFixtureBase.cs | 112 ++++++------ Fonlow.Testing.ServiceCore/README.md | 5 - .../ServiceCommandAgent.cs | 2 +- .../ServiceCommandsFixture.cs | 1 + README.md | 160 ++++++++++++------ TestReleaseAll.ps1 | 2 + .../IntegrationTestsCore.csproj | 6 +- .../ServiceCommandIntegrationTests.csproj | 6 +- 24 files changed, 331 insertions(+), 235 deletions(-) delete mode 100644 Fonlow.Testing.HttpCore/README.md delete mode 100644 Fonlow.Testing.ServiceCore/README.md create mode 100644 TestReleaseAll.ps1 diff --git a/.github/workflows/dotnetRelease.yml b/.github/workflows/dotnetRelease.yml index 1a57633..bf88931 100644 --- a/.github/workflows/dotnetRelease.yml +++ b/.github/workflows/dotnetRelease.yml @@ -24,9 +24,5 @@ jobs: run: dotnet restore - name: Build run: dotnet build --no-restore --configuration Release -# - name: Run DemoCoreWeb -# run: pwsh ./StartCoreWebApi.ps1 -# - name: Check Ports -# run: netstat -lntu - name: Test run: dotnet test --no-build --verbosity normal --configuration Release diff --git a/DemoCoreWeb/DemoCoreWeb.csproj b/DemoCoreWeb/DemoCoreWeb.csproj index 3d7bf72..1e2e728 100644 --- a/DemoCoreWeb/DemoCoreWeb.csproj +++ b/DemoCoreWeb/DemoCoreWeb.csproj @@ -5,7 +5,7 @@ - + diff --git a/DotNetPack.ps1 b/DotNetPack.ps1 index f4b2ec9..69c0dc4 100644 --- a/DotNetPack.ps1 +++ b/DotNetPack.ps1 @@ -1,4 +1,4 @@ -$packCmd = 'dotnet pack $Name --no-build --output C:/NugetLocalFeeds --configuration Release' +$packCmd = 'dotnet pack $Name --no-build --output ./Release --configuration Release' $projList = 'Fonlow.Testing.HttpCore/Fonlow.Testing.HttpCore.csproj', 'Fonlow.Testing.ServiceCore/Fonlow.Testing.ServiceCore.csproj' foreach($name in $projList){ Invoke-Expression $ExecutionContext.InvokeCommand.ExpandString($packCmd) diff --git a/Fonlow.Testing.HttpCore/AuthHttpClients.cs b/Fonlow.Testing.HttpCore/AuthHttpClients.cs index 3e9fa2f..865d65d 100644 --- a/Fonlow.Testing.HttpCore/AuthHttpClients.cs +++ b/Fonlow.Testing.HttpCore/AuthHttpClients.cs @@ -8,6 +8,7 @@ namespace Fonlow.Testing /// /// A dictionary of HttpClientWithUserName /// + [Obsolete("In favour of derived classes of HttpClientWithUsername in the integration test suites")] public class AuthHttpClients: IDisposable { public AuthHttpClients() : this(null) diff --git a/Fonlow.Testing.HttpCore/DefaultHttpClient.cs b/Fonlow.Testing.HttpCore/DefaultHttpClient.cs index 00ab1ab..63e7a70 100644 --- a/Fonlow.Testing.HttpCore/DefaultHttpClient.cs +++ b/Fonlow.Testing.HttpCore/DefaultHttpClient.cs @@ -6,6 +6,7 @@ namespace Fonlow.Testing /// /// HttpClient wrapped read test settings from appsettings.json, and ignore SSL certificates. /// + [Obsolete("In favour of BasicHttpClient")] public class DefaultHttpClient : IDisposable { public DefaultHttpClient(HttpMessageHandler handler) diff --git a/Fonlow.Testing.HttpCore/DefaultHttpClientWithUsername.cs b/Fonlow.Testing.HttpCore/DefaultHttpClientWithUsername.cs index e20d780..145be41 100644 --- a/Fonlow.Testing.HttpCore/DefaultHttpClientWithUsername.cs +++ b/Fonlow.Testing.HttpCore/DefaultHttpClientWithUsername.cs @@ -6,6 +6,7 @@ namespace Fonlow.Testing /// Provide an authorized HttpClient instance with uri and username/password defined in appsettings.json: /// BaseUrl, Username and Password. /// + [Obsolete("In favour of ServiceCommand along with its username/password pairs")] public class DefaultHttpClientWithUsername : HttpClientWithUsername { public DefaultHttpClientWithUsername() : this(null) diff --git a/Fonlow.Testing.HttpCore/Fonlow.Testing.HttpCore.csproj b/Fonlow.Testing.HttpCore/Fonlow.Testing.HttpCore.csproj index dd49750..bef4eee 100644 --- a/Fonlow.Testing.HttpCore/Fonlow.Testing.HttpCore.csproj +++ b/Fonlow.Testing.HttpCore/Fonlow.Testing.HttpCore.csproj @@ -1,36 +1,32 @@ - - - - net8.0 - true - Zijian Huang - Setup http client resources - Copyright © Fonlow 2015-$([System.DateTime]::Now.Year) - MIT - https://github.com/zijianhuang/FonlowTesting - xunit nunit mstest unittesting iisexpress iis webapi restful dotnet - en - 3.4 - Upgraded to .NET 8. - README.md - latest-all - - - - true - snupkg - true - true - true - - - - - - - - - - - - + + + + net8.0 + true + Zijian Huang + Setup http client resources + Copyright © Fonlow 2015-$([System.DateTime]::Now.Year) + MIT + https://github.com/zijianhuang/FonlowTesting + xunit nunit mstest unittesting iisexpress iis webapi restful dotnet + en + 3.4 + Upgraded to .NET 8. + README.md + latest-all + + + + true + snupkg + true + true + true + + + + + + + + diff --git a/Fonlow.Testing.HttpCore/HttpClientWithUsername.cs b/Fonlow.Testing.HttpCore/HttpClientWithUsername.cs index c2ef640..14569e8 100644 --- a/Fonlow.Testing.HttpCore/HttpClientWithUsername.cs +++ b/Fonlow.Testing.HttpCore/HttpClientWithUsername.cs @@ -2,7 +2,8 @@ using System.Collections.Generic; using System.Diagnostics; using System.Net.Http; -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; +//using Newtonsoft.Json.Linq; namespace Fonlow.Testing { @@ -102,7 +103,7 @@ void AnalyzeToken() if (String.IsNullOrEmpty(text)) return; - var jObject = JObject.Parse(text); + var jObject = JsonObject.Parse(text); var accessTokenObject = jObject["access_token"]; var expiriesInObject = jObject["expires_in"]; var tokenTypeObject = jObject["token_type"]; diff --git a/Fonlow.Testing.HttpCore/README.md b/Fonlow.Testing.HttpCore/README.md deleted file mode 100644 index 02c9a28..0000000 --- a/Fonlow.Testing.HttpCore/README.md +++ /dev/null @@ -1,5 +0,0 @@ -HttpClient wrapper classes to be used in xUnit IClassFixture. - -**Remarks:** - -* DD NOT use the claases with auth features in a production program, since these classes are for the convenience of integration testing. \ No newline at end of file diff --git a/Fonlow.Testing.HttpCore/TestingSettings.cs b/Fonlow.Testing.HttpCore/TestingSettings.cs index 2f3d7f2..b606773 100644 --- a/Fonlow.Testing.HttpCore/TestingSettings.cs +++ b/Fonlow.Testing.HttpCore/TestingSettings.cs @@ -1,10 +1,16 @@ using Microsoft.Extensions.Configuration; using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Reflection; namespace Fonlow.Testing { + /// + /// Data model of the "Testing" section "appsettings.json" and optionally "appsettings.BuildConfiguration.json"; + /// and the singleton object to access the settings read from the JSON files + /// public sealed class TestingSettings { private TestingSettings() @@ -40,8 +46,41 @@ static TestingSettings Create() static string GetBuildConfiguration() { - var assemblyConfigurationAttribute = Assembly.GetExecutingAssembly().GetCustomAttribute(); - return assemblyConfigurationAttribute?.Configuration; + var executingAssembly = Assembly.GetExecutingAssembly(); + var location = executingAssembly.Location; + var dir = Path.GetDirectoryName(location); + var pathNames = Directory.GetFiles(dir, "*.dll"); + List testAssemblies = new List(); + foreach (var p in pathNames) + { + try + { + var a = Assembly.LoadFile(p); + var referencedAssemblies = a.GetReferencedAssemblies(); + if (referencedAssemblies.Any(d => d.Name == "xunit.core") && !Path.GetFileName(p).StartsWith("xunit.", StringComparison.OrdinalIgnoreCase)) + { + testAssemblies.Add(a); + } + } + catch (FileLoadException) + { + continue; + } + catch (BadImageFormatException) + { + continue; + } + } + + if (testAssemblies.Count > 0) + { + var assemblyConfigurationAttribute = testAssemblies[0].GetCustomAttribute(); + return assemblyConfigurationAttribute?.Configuration; + } + else + { + return "Debug"; + } } } @@ -86,7 +125,7 @@ static string GetBuildConfiguration() /// /// Build configuration such as Debug, Release or whatever custom build configuration. - /// ServiceCommandFixture will replace {BuildConfiguration} in arguments with this. + /// ServiceCommandFixture will replace {BuildConfiguration} in commandPath and arguments with this. /// public string BuildConfiguration { get; private set; } } @@ -108,5 +147,11 @@ public sealed class ServiceCommand public int Delay { get; set; } public string ConnectionString { get; set; } public string BaseUrl { get; set; } + + /// + /// For testing with many different user credentials with different authorization. + /// + /// Obviously 2FA and alike are not welcome. Good enough for integration tests, but not E2E. + public UsernamePassword[] Users { get; set; } } } diff --git a/Fonlow.Testing.ServiceCore/DeploymentItemFixture.cs b/Fonlow.Testing.ServiceCore/DeploymentItemFixture.cs index af2e348..96646f1 100644 --- a/Fonlow.Testing.ServiceCore/DeploymentItemFixture.cs +++ b/Fonlow.Testing.ServiceCore/DeploymentItemFixture.cs @@ -4,6 +4,10 @@ namespace Fonlow.Testing { + /// + /// Copy files from source to destination. If file exists, copy only newer. + /// + [Obsolete("In favour of PowerShell scripts")] public class DeploymentItemFixture { public DeploymentItemFixture() diff --git a/Fonlow.Testing.ServiceCore/DirFunctions.cs b/Fonlow.Testing.ServiceCore/DirFunctions.cs index 5bacd0d..4134fcc 100644 --- a/Fonlow.Testing.ServiceCore/DirFunctions.cs +++ b/Fonlow.Testing.ServiceCore/DirFunctions.cs @@ -1,32 +1,34 @@ -using System.IO; -using System.Linq; - -namespace Fonlow.Testing +using System; +using System.IO; +using System.Linq; + +namespace Fonlow.Testing { - public static class DirFunctions - { + public static class DirFunctions + { /// /// Get Visual Studio Sln dir. /// /// - /// - public static DirectoryInfo GetSlnDir(string dir) - { - var d = new DirectoryInfo(dir); - - DirectoryInfo[] ds; - do - { - d = d.Parent; - if (d == null) - break; - - ds = d.EnumerateDirectories(".vs", SearchOption.TopDirectoryOnly).ToArray(); - } - while (ds.Length == 0); - - return d; - } - - } -} + /// + [Obsolete("IIS Legacy")] + public static DirectoryInfo GetSlnDir(string dir) + { + var d = new DirectoryInfo(dir); + + DirectoryInfo[] ds; + do + { + d = d.Parent; + if (d == null) + break; + + ds = d.EnumerateDirectories(".vs", SearchOption.TopDirectoryOnly).ToArray(); + } + while (ds.Length == 0); + + return d; + } + + } +} diff --git a/Fonlow.Testing.ServiceCore/Fonlow.Testing.ServiceCore.csproj b/Fonlow.Testing.ServiceCore/Fonlow.Testing.ServiceCore.csproj index b3d5cd3..ae6abd8 100644 --- a/Fonlow.Testing.ServiceCore/Fonlow.Testing.ServiceCore.csproj +++ b/Fonlow.Testing.ServiceCore/Fonlow.Testing.ServiceCore.csproj @@ -30,6 +30,6 @@ - + diff --git a/Fonlow.Testing.ServiceCore/IisExpressAgent.cs b/Fonlow.Testing.ServiceCore/IisExpressAgent.cs index c926285..5457479 100644 --- a/Fonlow.Testing.ServiceCore/IisExpressAgent.cs +++ b/Fonlow.Testing.ServiceCore/IisExpressAgent.cs @@ -1,17 +1,17 @@ -using System; - -namespace Fonlow.Testing +using System; + +namespace Fonlow.Testing { - /// - /// To be used alone without fixture. - /// - [Obsolete("In favor of ServiceCommandAgent")] - public class IisExpressAgent: IisExpressAgentBase - { - public IisExpressAgent(): base(TestingSettings.Instance.HostSite, TestingSettings.Instance.HostSiteApplicationPool, - TestingSettings.Instance.SlnName, TestingSettings.Instance.SlnRoot) - { - - } - } -} + /// + /// To be used alone without fixture. + /// + [Obsolete("In favor of ServiceCommandAgent")] + public class IisExpressAgent: IisExpressAgentBase + { + public IisExpressAgent(): base(TestingSettings.Instance.HostSite, TestingSettings.Instance.HostSiteApplicationPool, + TestingSettings.Instance.SlnName, TestingSettings.Instance.SlnRoot) + { + + } + } +} diff --git a/Fonlow.Testing.ServiceCore/IisExpressAgentBase.cs b/Fonlow.Testing.ServiceCore/IisExpressAgentBase.cs index 465db9e..ced2ea5 100644 --- a/Fonlow.Testing.ServiceCore/IisExpressAgentBase.cs +++ b/Fonlow.Testing.ServiceCore/IisExpressAgentBase.cs @@ -3,12 +3,12 @@ namespace Fonlow.Testing { - /// - /// For starting and stoping IIS Express - /// - /// The IIS Express config is at - [Obsolete("In favor of ServiceCommandAgent")] - public class IisExpressAgentBase + /// + /// For starting and stoping IIS Express + /// + /// The IIS Express config is at + [Obsolete("In favor of ServiceCommandAgent")] + public class IisExpressAgentBase { public IisExpressAgentBase(string hostSite, string hostSiteApplicationPool, string slnName, string slnRoot) { diff --git a/Fonlow.Testing.ServiceCore/IisExpressFixture.cs b/Fonlow.Testing.ServiceCore/IisExpressFixture.cs index 0ab05cb..ecffdbd 100644 --- a/Fonlow.Testing.ServiceCore/IisExpressFixture.cs +++ b/Fonlow.Testing.ServiceCore/IisExpressFixture.cs @@ -1,13 +1,13 @@ -using System; - -namespace Fonlow.Testing -{ - [Obsolete("In favor of ServiceCommandFixture")] - public class IisExpressFixture : IisExpressFixtureBase - { - public IisExpressFixture(): base(!String.IsNullOrWhiteSpace(TestingSettings.Instance.HostSite)) - { - - } - } -} +using System; + +namespace Fonlow.Testing +{ + [Obsolete("In favor of ServiceCommandFixture")] + public class IisExpressFixture : IisExpressFixtureBase + { + public IisExpressFixture(): base(!String.IsNullOrWhiteSpace(TestingSettings.Instance.HostSite)) + { + + } + } +} diff --git a/Fonlow.Testing.ServiceCore/IisExpressFixtureBase.cs b/Fonlow.Testing.ServiceCore/IisExpressFixtureBase.cs index 9615489..ffe9a3d 100644 --- a/Fonlow.Testing.ServiceCore/IisExpressFixtureBase.cs +++ b/Fonlow.Testing.ServiceCore/IisExpressFixtureBase.cs @@ -1,59 +1,59 @@ -using System; -using System.Diagnostics; - -namespace Fonlow.Testing +using System; +using System.Diagnostics; + +namespace Fonlow.Testing { - /// - /// Launch IIS Express if AppSettings["Testing_UseIisExpress"] is true, using the following settings - /// AppSettings["Testing_HostSite"]; AppSettings["Testing_HostSiteApplicationPool"]. This class is mainly for - /// launching IIS Express only once for one or multiple test classes that talk to the same Website. - /// + /// + /// Launch IIS Express if AppSettings["Testing_UseIisExpress"] is true, using the following settings + /// AppSettings["Testing_HostSite"]; AppSettings["Testing_HostSiteApplicationPool"]. This class is mainly for + /// launching IIS Express only once for one or multiple test classes that talk to the same Website. + /// [Obsolete("In favor of ServiceCommandFixture")] - public class IisExpressFixtureBase : IDisposable - { - /// - /// Create the fixture. And this constructor is also used in XUnit.ICollectionFixture. - /// - public IisExpressFixtureBase(bool active) - { - if (active) - { - iisExpressAgent = new IisExpressAgent(); - iisExpressAgent.Start(); - } - } - - readonly IisExpressAgent iisExpressAgent; - - - bool disposed; - - // implements IDisposable - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (!disposed) - { - // if this is a dispose call dispose on all state you - // hold, and take yourself off the Finalization queue. - if (disposing) - { - if (iisExpressAgent!=null) - { - iisExpressAgent.Stop(); - Trace.TraceInformation("IIS Express stoped."); - } - } - - disposed = true; - } - } - - } - + public class IisExpressFixtureBase : IDisposable + { + /// + /// Create the fixture. And this constructor is also used in XUnit.ICollectionFixture. + /// + public IisExpressFixtureBase(bool active) + { + if (active) + { + iisExpressAgent = new IisExpressAgent(); + iisExpressAgent.Start(); + } + } + + readonly IisExpressAgent iisExpressAgent; + + + bool disposed; + + // implements IDisposable + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!disposed) + { + // if this is a dispose call dispose on all state you + // hold, and take yourself off the Finalization queue. + if (disposing) + { + if (iisExpressAgent!=null) + { + iisExpressAgent.Stop(); + Trace.TraceInformation("IIS Express stoped."); + } + } + + disposed = true; + } + } + + } + } \ No newline at end of file diff --git a/Fonlow.Testing.ServiceCore/README.md b/Fonlow.Testing.ServiceCore/README.md deleted file mode 100644 index 4e9582c..0000000 --- a/Fonlow.Testing.ServiceCore/README.md +++ /dev/null @@ -1,5 +0,0 @@ -Classes for launching IIS Express and DotNet Kestrel, to be used in xUnit ICollectionFixture. - -**Remarks:** - -* DD NOT use the claases with auth features in a production program, since these classes are for the convenience of integration testing. \ No newline at end of file diff --git a/Fonlow.Testing.ServiceCore/ServiceCommandAgent.cs b/Fonlow.Testing.ServiceCore/ServiceCommandAgent.cs index 7242492..261bd93 100644 --- a/Fonlow.Testing.ServiceCore/ServiceCommandAgent.cs +++ b/Fonlow.Testing.ServiceCore/ServiceCommandAgent.cs @@ -36,7 +36,7 @@ public void Start() info = new ProcessStartInfo(command, ServicCommand.Arguments) { UseShellExecute = true, - WorkingDirectory = workingDir + WorkingDirectory = workingDir, }; Console.WriteLine($"Working Dir: {workingDir}; Current Dir: {System.IO.Directory.GetCurrentDirectory()}"); diff --git a/Fonlow.Testing.ServiceCore/ServiceCommandsFixture.cs b/Fonlow.Testing.ServiceCore/ServiceCommandsFixture.cs index 1bc572f..f7e002d 100644 --- a/Fonlow.Testing.ServiceCore/ServiceCommandsFixture.cs +++ b/Fonlow.Testing.ServiceCore/ServiceCommandsFixture.cs @@ -16,6 +16,7 @@ public ServiceCommandsFixture() foreach (var item in TestingSettings.Instance.ServiceCommands) { item.Arguments = item.Arguments?.Replace("{BuildConfiguration}", TestingSettings.Instance.BuildConfiguration); + item.CommandPath = item.CommandPath?.Replace("{BuildConfiguration}", TestingSettings.Instance.BuildConfiguration); var serviceCommandAgent = new ServiceCommandAgent(item); serviceCommandAgent.Start(); serviceCommandAgents.Add(serviceCommandAgent); diff --git a/README.md b/README.md index 4081658..5faf9f3 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,12 @@ This project is to deliver some light-weight helper classes for developers to qu ### For .NET Core 8.0 + -* [Fonlow.Testing.ServiceCore](https://www.nuget.org/packages/Fonlow.Testing.ServiceCore/) -* [Fonlow.Testing.HttpCore](https://www.nuget.org/packages/Fonlow.Testing.HttpCore/) +* Package [Fonlow.Testing.ServiceCore](https://www.nuget.org/packages/Fonlow.Testing.ServiceCore/) + * Class [ServiceCommandsFixture](https://github.com/zijianhuang/FonlowTesting/blob/master/Fonlow.Testing.ServiceCore/ServiceCommandsFixture.cs) +* Package [Fonlow.Testing.HttpCore](https://www.nuget.org/packages/Fonlow.Testing.HttpCore/) + * Class [BasicHttpClient](https://github.com/zijianhuang/FonlowTesting/blob/master/Fonlow.Testing.HttpCore/BasicHttpClient.cs) + * Class [HttpClientWithUsername](https://github.com/zijianhuang/FonlowTesting/blob/master/Fonlow.Testing.HttpCore/HttpClientWithUsername.cs) + * Class [TestingSettings](https://github.com/zijianhuang/FonlowTesting/blob/master/Fonlow.Testing.HttpCore/TestingSettings.cs) * [Examples of Integration Test Suite](https://github.com/zijianhuang/DemoCoreWeb/tree/master/Tests/ServiceCommandIntegrationTests) ## Examples @@ -24,29 +28,34 @@ This project is to deliver some light-weight helper classes for developers to qu appsettings.json: ```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 - } - ], - - "Username": "admin", - "Password": "Pppppp*8" - } + "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 + } + ], +... +... + } } ``` -Integration Test Suite: +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: ```csharp public class TestConstants @@ -123,54 +132,96 @@ appsettings.Debug.json: ```csharp public sealed class TestingSettings { - public string Username { get; set; } - public string Password { get; set; } + public string Username { get; set; } + public string Password { get; set; } - /// - /// For testing with many different user credentials. - /// - public UsernamePassword[] Users { get; set; } + /// + /// For testing with many different user credentials. + /// + public UsernamePassword[] Users { get; set; } - public ServiceCommand[] ServiceCommands { get; set; } + public ServiceCommand[] ServiceCommands { get; set; } - /// - /// Build configuration such as Debug, Release or whatever custom build configuration. - /// ServiceCommandFixture will replace {BuildConfiguration} in arguments with this. - /// - public string BuildConfiguration { get; private set; } + /// + /// Build configuration such as Debug, Release or whatever custom build configuration. + /// ServiceCommandFixture will replace {BuildConfiguration} in arguments with this. + /// + public string BuildConfiguration { get; private set; } } public sealed class UsernamePassword { - public string Username { get; set; } - public string Password { get; set; } + public string Username { get; set; } + public string Password { get; set; } } public sealed class ServiceCommand { - public string CommandPath { get; set; } - public string Arguments { get; set; } - - /// - /// 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. - /// - public int Delay { get; set; } - public string ConnectionString { get; set; } - public string BaseUrl { get; set; } + public string CommandPath { get; set; } + public string Arguments { get; set; } + + /// + /// 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. + /// + public int Delay { get; set; } + public string ConnectionString { get; set; } + public string BaseUrl { get; set; } } ``` -## Recommended/Expected Practices +## More Examples of Launching Services/Commands -The design of these helper classes are based on the author's understanding about software engineering. If you share the following understandings, you may find the helper classes could be useful giving you smoother developer experience during DevOps or developing cloud-based applications. +### In-house Web API -For the sake of DevOps, ensure the application codes have zero or the least knowledge of the IT operations. +```json +{ + "CommandPath": "dotnet", + "Arguments": "run --project ../../../../../DemoCoreWeb/DemoCoreWeb.csproj --no-build --configuration {BuildConfiguration}", +} +``` +Hints: -For the sake of Cloud computing or so called cloud native, ensure the application codes or the primary logics have zero or the least knowledge of the host applications and the cloud environment, after ensuring the overall architectural design and software design have the least coupling with the cloud environment. +* The current directory of the launched Web API is the directory containing the csproj file. -When doing CI configuration, prefer configuration convention over fine-grained configuration. For example, build the sln, then run all tests, rather than craft fine-grained controls over each library and application of the same sln. +```json +{ + "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. + +```json +{ + "CommandPath": "../../../../../DemoCoreWeb/bin/{BuildConfiguration}/net8.0/DemoCoreWeb.exe", +} +``` + +Hints: -There are definitely some legitimate cases that make the above recommendations sound illegitimate . +* 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: +```yml + - 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 @@ -178,4 +229,9 @@ The libraries of helper classes have been developed since the .NET Framework era * [Functional Testing ASP.NET Core Apps](https://learn.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/test-asp-net-core-mvc-apps#functional-testing-aspnet-core-apps) * [Docker Compose Fixture](https://github.com/devjoes/DockerComposeFixture) -* [Integration Test with .Net Core and Docker](https://ademcatamak.medium.com/integration-test-with-net-core-and-docker-21b241f7372) \ No newline at end of file +* [Integration Test with .Net Core and Docker](https://ademcatamak.medium.com/integration-test-with-net-core-and-docker-21b241f7372) +* [BenchmarkDotNet](https://github.com/dotnet/BenchmarkDotNet) + +**References:** + +* [Different Types of Tests](https://www.atlassian.com/continuous-delivery/software-testing/types-of-software-testing) \ No newline at end of file diff --git a/TestReleaseAll.ps1 b/TestReleaseAll.ps1 new file mode 100644 index 0000000..9faff31 --- /dev/null +++ b/TestReleaseAll.ps1 @@ -0,0 +1,2 @@ +cd $PSScriptRoot +dotnet test --verbosity normal --configuration Release --no-build \ No newline at end of file diff --git a/Tests/IntegrationTestsCore/IntegrationTestsCore.csproj b/Tests/IntegrationTestsCore/IntegrationTestsCore.csproj index 1308f87..bac9e40 100644 --- a/Tests/IntegrationTestsCore/IntegrationTestsCore.csproj +++ b/Tests/IntegrationTestsCore/IntegrationTestsCore.csproj @@ -17,9 +17,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Tests/ServiceCommandTests/ServiceCommandIntegrationTests.csproj b/Tests/ServiceCommandTests/ServiceCommandIntegrationTests.csproj index 1920484..3f232fe 100644 --- a/Tests/ServiceCommandTests/ServiceCommandIntegrationTests.csproj +++ b/Tests/ServiceCommandTests/ServiceCommandIntegrationTests.csproj @@ -25,9 +25,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive