Tutorial

2.2 Add a solution and a test project

The tests live in a project of their own under tests/, which chapter 1's project file already leaves out of the application. A solution file at the root holds both projects:

dotnet new sln -n Shopfront
mkdir -p tests/Shopfront.Tests

Add the test packages to Directory.Packages.props, beside the Trax ones:

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
    <CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
  </PropertyGroup>
 
  <ItemGroup>
    <PackageVersion Include="Trax.Core" Version="1.68.0" />
    <PackageVersion Include="Trax.Core.Testing" Version="1.68.0" />
    <PackageVersion Include="Trax.Effect" Version="1.68.0" />
    <PackageVersion Include="Trax.Effect.Data.InMemory" Version="1.68.0" />
    <PackageVersion Include="Trax.Effect.Provider.Parameter" Version="1.68.0" />
    <PackageVersion Include="Trax.Mediator" Version="1.68.0" />
    <PackageVersion Include="Trax.Mediator.Testing" Version="1.68.0" />
  </ItemGroup>
 
  <ItemGroup>
    <PackageVersion Include="AwesomeAssertions" Version="9.6.0" />
    <PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.12" />
    <PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.10.1" />
    <!-- NUnit3TestAdapter pulls these at versions deprecated as Legacy; pin newer ones. -->
    <PackageVersion Include="Microsoft.Testing.Extensions.VSTestBridge" Version="2.5.1" />
    <PackageVersion Include="Microsoft.Testing.Platform.MSBuild" Version="2.5.1" />
    <PackageVersion Include="NUnit" Version="5.0.0" />
    <PackageVersion Include="NUnit.Analyzers" Version="4.15.0" />
    <PackageVersion Include="NUnit3TestAdapter" Version="6.3.0" />
  </ItemGroup>
</Project>

tests/Shopfront.Tests/Shopfront.Tests.csproj:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <IsPackable>false</IsPackable>
    <IsTestProject>true</IsTestProject>
  </PropertyGroup>
 
  <ItemGroup>
    <ProjectReference Include="..\..\Shopfront.csproj" />
  </ItemGroup>
 
  <ItemGroup>
    <PackageReference Include="AwesomeAssertions" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" />
    <PackageReference Include="NUnit" />
    <PackageReference Include="NUnit.Analyzers" />
    <PackageReference Include="NUnit3TestAdapter" />
    <PackageReference Include="Trax.Core.Testing" />
    <PackageReference Include="Trax.Mediator.Testing" />
  </ItemGroup>
</Project>

Then add both projects to the solution:

dotnet sln add Shopfront.csproj tests/Shopfront.Tests/Shopfront.Tests.csproj

The junctions and the types they pass each other are internal, so nothing in the application outside the train can depend on them. The tests are the one exception, and the application says so. Add one line to Shopfront.csproj:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <!-- The tests live under tests/, in a project of their own. -->
    <DefaultItemExcludes>$(DefaultItemExcludes);tests/**</DefaultItemExcludes>
  </PropertyGroup>
 
  <ItemGroup>
    <!-- The junctions are internal; their tests are the one project that may see them. -->
    <InternalsVisibleTo Include="Shopfront.Tests" />
  </ItemGroup>
 
  <ItemGroup>
    <PackageReference Include="Trax.Core" />
    <PackageReference Include="Trax.Effect" />
    <PackageReference Include="Trax.Effect.Data.InMemory" />
    <PackageReference Include="Trax.Effect.Provider.Parameter" />
    <PackageReference Include="Trax.Mediator" />
  </ItemGroup>
</Project>

tests/Shopfront.Tests/GlobalUsings.cs:

global using AwesomeAssertions;
global using NUnit.Framework;

By the end of the chapter the test project looks like this:

tests/
└── Shopfront.Tests/
    ├── Shopfront.Tests.csproj
    ├── GlobalUsings.cs
    ├── ArchitectureGuards.cs
    ├── UnitTests/
    │   ├── PriceCartJunctionTests.cs
    │   ├── ReserveStockJunctionTests.cs
    │   └── TakePaymentJunctionTests.cs
    └── IntegrationTests/
        ├── PlaceOrderTrainTests.cs
        └── HostTests.cs

Test names say what is called, in what situation, and what should happen: Run_EmptyCart_Throws.

SDK Reference

ITrainBus | UseInMemory | SaveTrainParameters | Metadata | Mediator testing | Architecture guards


Next: 2.3 Test a junction